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 188c2c66affSColin Finck ASSERT(MftId < 0x10); 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, 249c2c66affSColin Finck PNTFS_FCB * FoundFCB) 250c2c66affSColin Finck { 251c2c66affSColin Finck PNTFS_FCB ParentFcb; 252c2c66affSColin Finck PNTFS_FCB Fcb; 253c2c66affSColin Finck NTSTATUS Status; 254c2c66affSColin Finck PWSTR AbsFileName = NULL; 255c2c66affSColin Finck 256c2c66affSColin Finck DPRINT1("NtfsOpenFile(%p, %p, %S, %p)\n", DeviceExt, FileObject, FileName, FoundFCB); 257c2c66affSColin Finck 258c2c66affSColin Finck *FoundFCB = NULL; 259c2c66affSColin Finck 260c2c66affSColin Finck if (FileObject->RelatedFileObject) 261c2c66affSColin Finck { 262c2c66affSColin Finck DPRINT("Converting relative filename to absolute filename\n"); 263c2c66affSColin Finck 264c2c66affSColin Finck Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject, 265c2c66affSColin Finck FileName, 266c2c66affSColin Finck &AbsFileName); 267c2c66affSColin Finck if (AbsFileName) FileName = AbsFileName; 268c2c66affSColin Finck if (!NT_SUCCESS(Status)) 269c2c66affSColin Finck { 270c2c66affSColin Finck return Status; 271c2c66affSColin Finck } 272c2c66affSColin Finck } 273c2c66affSColin Finck 274c2c66affSColin Finck //FIXME: Get canonical path name (remove .'s, ..'s and extra separators) 275c2c66affSColin Finck 276c2c66affSColin Finck DPRINT("PathName to open: %S\n", FileName); 277c2c66affSColin Finck 278c2c66affSColin Finck /* try first to find an existing FCB in memory */ 279c2c66affSColin Finck DPRINT("Checking for existing FCB in memory\n"); 280c2c66affSColin Finck Fcb = NtfsGrabFCBFromTable(DeviceExt, 281c2c66affSColin Finck FileName); 282c2c66affSColin Finck if (Fcb == NULL) 283c2c66affSColin Finck { 284c2c66affSColin Finck DPRINT("No existing FCB found, making a new one if file exists.\n"); 285c2c66affSColin Finck Status = NtfsGetFCBForFile(DeviceExt, 286c2c66affSColin Finck &ParentFcb, 287c2c66affSColin Finck &Fcb, 288c2c66affSColin Finck FileName); 289c2c66affSColin Finck if (ParentFcb != NULL) 290c2c66affSColin Finck { 291c2c66affSColin Finck NtfsReleaseFCB(DeviceExt, 292c2c66affSColin Finck ParentFcb); 293c2c66affSColin Finck } 294c2c66affSColin Finck 295c2c66affSColin Finck if (!NT_SUCCESS (Status)) 296c2c66affSColin Finck { 297c2c66affSColin Finck DPRINT("Could not make a new FCB, status: %x\n", Status); 298c2c66affSColin Finck 299c2c66affSColin Finck if (AbsFileName) 300c2c66affSColin Finck ExFreePool(AbsFileName); 301c2c66affSColin Finck 302c2c66affSColin Finck return Status; 303c2c66affSColin Finck } 304c2c66affSColin Finck } 305c2c66affSColin Finck 306c2c66affSColin Finck DPRINT("Attaching FCB to fileObject\n"); 307c2c66affSColin Finck Status = NtfsAttachFCBToFileObject(DeviceExt, 308c2c66affSColin Finck Fcb, 309c2c66affSColin Finck FileObject); 310c2c66affSColin Finck 311c2c66affSColin Finck if (AbsFileName) 312c2c66affSColin Finck ExFreePool(AbsFileName); 313c2c66affSColin Finck 314c2c66affSColin Finck *FoundFCB = Fcb; 315c2c66affSColin Finck 316c2c66affSColin Finck return Status; 317c2c66affSColin Finck } 318c2c66affSColin Finck 319c2c66affSColin Finck 320c2c66affSColin Finck /* 321c2c66affSColin Finck * FUNCTION: Opens a file 322c2c66affSColin Finck */ 323c2c66affSColin Finck static 324c2c66affSColin Finck NTSTATUS 325c2c66affSColin Finck NtfsCreateFile(PDEVICE_OBJECT DeviceObject, 326c2c66affSColin Finck PIRP Irp) 327c2c66affSColin Finck { 328c2c66affSColin Finck PDEVICE_EXTENSION DeviceExt; 329c2c66affSColin Finck PIO_STACK_LOCATION Stack; 330c2c66affSColin Finck PFILE_OBJECT FileObject; 331c2c66affSColin Finck ULONG RequestedDisposition; 332c2c66affSColin Finck ULONG RequestedOptions; 333c2c66affSColin Finck PNTFS_FCB Fcb = NULL; 334c2c66affSColin Finck // PWSTR FileName; 335c2c66affSColin Finck NTSTATUS Status; 336c2c66affSColin Finck UNICODE_STRING FullPath; 337c2c66affSColin Finck 338c2c66affSColin Finck DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, Irp); 339c2c66affSColin Finck 340c2c66affSColin Finck DeviceExt = DeviceObject->DeviceExtension; 341c2c66affSColin Finck ASSERT(DeviceExt); 342c2c66affSColin Finck Stack = IoGetCurrentIrpStackLocation (Irp); 343c2c66affSColin Finck ASSERT(Stack); 344c2c66affSColin Finck 345c2c66affSColin Finck RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); 346c2c66affSColin Finck RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; 347c2c66affSColin Finck // PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; 348c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE && 349c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE) 350c2c66affSColin Finck { 351c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 352c2c66affSColin Finck } 353c2c66affSColin Finck 354c2c66affSColin Finck /* Deny create if the volume is locked */ 355c2c66affSColin Finck if (DeviceExt->Flags & VCB_VOLUME_LOCKED) 356c2c66affSColin Finck { 357c2c66affSColin Finck return STATUS_ACCESS_DENIED; 358c2c66affSColin Finck } 359c2c66affSColin Finck 360c2c66affSColin Finck FileObject = Stack->FileObject; 361c2c66affSColin Finck 362c2c66affSColin Finck if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID) 363c2c66affSColin Finck { 364c2c66affSColin Finck ULONGLONG MFTId; 365c2c66affSColin Finck 366c2c66affSColin Finck if (FileObject->FileName.Length != sizeof(ULONGLONG)) 367c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 368c2c66affSColin Finck 369c2c66affSColin Finck MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK; 370c2c66affSColin Finck if (MFTId < 0x10) 371c2c66affSColin Finck { 372c2c66affSColin Finck Status = NtfsOpenFileById(DeviceExt, FileObject, MFTId, &Fcb); 373c2c66affSColin Finck } 374c2c66affSColin Finck else 375c2c66affSColin Finck { 376c2c66affSColin Finck Status = NtfsMoonWalkID(DeviceExt, MFTId, &FullPath); 377c2c66affSColin Finck } 378c2c66affSColin Finck 379c2c66affSColin Finck if (!NT_SUCCESS(Status)) 380c2c66affSColin Finck { 381c2c66affSColin Finck return Status; 382c2c66affSColin Finck } 383c2c66affSColin Finck 384c2c66affSColin Finck DPRINT1("Open by ID: %I64x -> %wZ\n", (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK, &FullPath); 385c2c66affSColin Finck } 386c2c66affSColin Finck 387c2c66affSColin Finck /* This a open operation for the volume itself */ 388c2c66affSColin Finck if (FileObject->FileName.Length == 0 && 389c2c66affSColin Finck (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL)) 390c2c66affSColin Finck { 391c2c66affSColin Finck if (RequestedDisposition != FILE_OPEN && 392c2c66affSColin Finck RequestedDisposition != FILE_OPEN_IF) 393c2c66affSColin Finck { 394c2c66affSColin Finck return STATUS_ACCESS_DENIED; 395c2c66affSColin Finck } 396c2c66affSColin Finck 397c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE) 398c2c66affSColin Finck { 399c2c66affSColin Finck return STATUS_NOT_A_DIRECTORY; 400c2c66affSColin Finck } 401c2c66affSColin Finck 402c2c66affSColin Finck NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject); 403c2c66affSColin Finck DeviceExt->VolumeFcb->RefCount++; 404c2c66affSColin Finck 405c2c66affSColin Finck Irp->IoStatus.Information = FILE_OPENED; 406c2c66affSColin Finck return STATUS_SUCCESS; 407c2c66affSColin Finck } 408c2c66affSColin Finck 409c2c66affSColin Finck if (Fcb == NULL) 410c2c66affSColin Finck { 411c2c66affSColin Finck Status = NtfsOpenFile(DeviceExt, 412c2c66affSColin Finck FileObject, 413c2c66affSColin Finck ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? FullPath.Buffer : FileObject->FileName.Buffer), 414c2c66affSColin Finck &Fcb); 415c2c66affSColin Finck 416c2c66affSColin Finck if (RequestedOptions & FILE_OPEN_BY_FILE_ID) 417c2c66affSColin Finck { 418c2c66affSColin Finck ExFreePoolWithTag(FullPath.Buffer, TAG_NTFS); 419c2c66affSColin Finck } 420c2c66affSColin Finck } 421c2c66affSColin Finck 422c2c66affSColin Finck if (NT_SUCCESS(Status)) 423c2c66affSColin Finck { 424c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE) 425c2c66affSColin Finck { 426c2c66affSColin Finck Irp->IoStatus.Information = FILE_EXISTS; 427c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 428c2c66affSColin Finck return STATUS_OBJECT_NAME_COLLISION; 429c2c66affSColin Finck } 430c2c66affSColin Finck 431c2c66affSColin Finck if (RequestedOptions & FILE_NON_DIRECTORY_FILE && 432c2c66affSColin Finck NtfsFCBIsDirectory(Fcb)) 433c2c66affSColin Finck { 434c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 435c2c66affSColin Finck return STATUS_FILE_IS_A_DIRECTORY; 436c2c66affSColin Finck } 437c2c66affSColin Finck 438c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE && 439c2c66affSColin Finck !NtfsFCBIsDirectory(Fcb)) 440c2c66affSColin Finck { 441c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 442c2c66affSColin Finck return STATUS_NOT_A_DIRECTORY; 443c2c66affSColin Finck } 444c2c66affSColin Finck 445c2c66affSColin Finck /* 446c2c66affSColin Finck * If it is a reparse point & FILE_OPEN_REPARSE_POINT, then allow opening it 447c2c66affSColin Finck * as a normal file. 448c2c66affSColin Finck * Otherwise, attempt to read reparse data and hand them to the Io manager 449c2c66affSColin Finck * with status reparse to force a reparse. 450c2c66affSColin Finck */ 451c2c66affSColin Finck if (NtfsFCBIsReparsePoint(Fcb) && 452c2c66affSColin Finck ((RequestedOptions & FILE_OPEN_REPARSE_POINT) != FILE_OPEN_REPARSE_POINT)) 453c2c66affSColin Finck { 454c2c66affSColin Finck PREPARSE_DATA_BUFFER ReparseData = NULL; 455c2c66affSColin Finck 456c2c66affSColin Finck Status = NtfsReadFCBAttribute(DeviceExt, Fcb, 457c2c66affSColin Finck AttributeReparsePoint, L"", 0, 458c2c66affSColin Finck (PVOID *)&Irp->Tail.Overlay.AuxiliaryBuffer); 459c2c66affSColin Finck if (NT_SUCCESS(Status)) 460c2c66affSColin Finck { 461c2c66affSColin Finck ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; 462c2c66affSColin Finck if (ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) 463c2c66affSColin Finck { 464c2c66affSColin Finck Status = STATUS_REPARSE; 465c2c66affSColin Finck } 466c2c66affSColin Finck else 467c2c66affSColin Finck { 468c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 469c2c66affSColin Finck ExFreePoolWithTag(ReparseData, TAG_NTFS); 470c2c66affSColin Finck } 471c2c66affSColin Finck } 472c2c66affSColin Finck 473c2c66affSColin Finck Irp->IoStatus.Information = ((Status == STATUS_REPARSE) ? ReparseData->ReparseTag : 0); 474c2c66affSColin Finck 475c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 476c2c66affSColin Finck return Status; 477c2c66affSColin Finck } 478c2c66affSColin Finck 479c2c66affSColin Finck if (RequestedDisposition == FILE_OVERWRITE || 480c2c66affSColin Finck RequestedDisposition == FILE_OVERWRITE_IF || 481c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE) 482c2c66affSColin Finck { 48384a1280fSTrevor Thompson PFILE_RECORD_HEADER fileRecord = NULL; 48484a1280fSTrevor Thompson PNTFS_ATTR_CONTEXT dataContext = NULL; 48584a1280fSTrevor Thompson ULONG DataAttributeOffset; 48684a1280fSTrevor Thompson LARGE_INTEGER Zero; 48784a1280fSTrevor Thompson Zero.QuadPart = 0; 48884a1280fSTrevor Thompson 489*037d8820STrevor Thompson if (!NtfsGlobalData->EnableWriteSupport) 490*037d8820STrevor Thompson { 491*037d8820STrevor Thompson DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n"); 492*037d8820STrevor Thompson NtfsCloseFile(DeviceExt, FileObject); 493*037d8820STrevor Thompson return STATUS_ACCESS_DENIED; 494*037d8820STrevor Thompson } 495*037d8820STrevor Thompson 49684a1280fSTrevor Thompson // TODO: check for appropriate access 49784a1280fSTrevor Thompson 49884a1280fSTrevor Thompson ExAcquireResourceExclusiveLite(&(Fcb->MainResource), TRUE); 49984a1280fSTrevor Thompson 50084a1280fSTrevor Thompson fileRecord = ExAllocatePoolWithTag(NonPagedPool, 50184a1280fSTrevor Thompson Fcb->Vcb->NtfsInfo.BytesPerFileRecord, 50284a1280fSTrevor Thompson TAG_NTFS); 50384a1280fSTrevor Thompson if (fileRecord) 50484a1280fSTrevor Thompson { 50584a1280fSTrevor Thompson 50684a1280fSTrevor Thompson Status = ReadFileRecord(Fcb->Vcb, 50784a1280fSTrevor Thompson Fcb->MFTIndex, 50884a1280fSTrevor Thompson fileRecord); 50984a1280fSTrevor Thompson if (!NT_SUCCESS(Status)) 51084a1280fSTrevor Thompson goto DoneOverwriting; 51184a1280fSTrevor Thompson 51284a1280fSTrevor Thompson // find the data attribute and set it's length to 0 (TODO: Handle Alternate Data Streams) 51384a1280fSTrevor Thompson Status = FindAttribute(Fcb->Vcb, fileRecord, AttributeData, L"", 0, &dataContext, &DataAttributeOffset); 51484a1280fSTrevor Thompson if (!NT_SUCCESS(Status)) 51584a1280fSTrevor Thompson goto DoneOverwriting; 51684a1280fSTrevor Thompson 51784a1280fSTrevor Thompson Status = SetAttributeDataLength(FileObject, Fcb, dataContext, DataAttributeOffset, fileRecord, &Zero); 51884a1280fSTrevor Thompson } 51984a1280fSTrevor Thompson else 52084a1280fSTrevor Thompson { 52184a1280fSTrevor Thompson Status = STATUS_NO_MEMORY; 52284a1280fSTrevor Thompson } 52384a1280fSTrevor Thompson 52484a1280fSTrevor Thompson DoneOverwriting: 52584a1280fSTrevor Thompson if (fileRecord) 52684a1280fSTrevor Thompson ExFreePool(fileRecord); 52784a1280fSTrevor Thompson if (dataContext) 52884a1280fSTrevor Thompson ReleaseAttributeContext(dataContext); 52984a1280fSTrevor Thompson 53084a1280fSTrevor Thompson ExReleaseResourceLite(&(Fcb->MainResource)); 53184a1280fSTrevor Thompson 53284a1280fSTrevor Thompson if (!NT_SUCCESS(Status)) 53384a1280fSTrevor Thompson { 534c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject); 53584a1280fSTrevor Thompson return Status; 53684a1280fSTrevor Thompson } 53784a1280fSTrevor Thompson 53884a1280fSTrevor Thompson if (RequestedDisposition == FILE_SUPERSEDE) 53984a1280fSTrevor Thompson { 54084a1280fSTrevor Thompson Irp->IoStatus.Information = FILE_SUPERSEDED; 54184a1280fSTrevor Thompson } 54284a1280fSTrevor Thompson else 54384a1280fSTrevor Thompson { 54484a1280fSTrevor Thompson Irp->IoStatus.Information = FILE_OVERWRITTEN; 54584a1280fSTrevor Thompson } 546c2c66affSColin Finck } 547c2c66affSColin Finck } 548c2c66affSColin Finck else 549c2c66affSColin Finck { 55058a13831STrevor Thompson /* HUGLY HACK: Can't create new files yet... */ 551c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE || 552c2c66affSColin Finck RequestedDisposition == FILE_OPEN_IF || 553c2c66affSColin Finck RequestedDisposition == FILE_OVERWRITE_IF || 554c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE) 555c2c66affSColin Finck { 556*037d8820STrevor Thompson if (!NtfsGlobalData->EnableWriteSupport) 557*037d8820STrevor Thompson { 558*037d8820STrevor Thompson DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n"); 559*037d8820STrevor Thompson NtfsCloseFile(DeviceExt, FileObject); 560*037d8820STrevor Thompson return STATUS_ACCESS_DENIED; 561*037d8820STrevor Thompson } 562*037d8820STrevor Thompson 5630409b316STrevor Thompson // Create the file record on disk 5640409b316STrevor Thompson Status = NtfsCreateFileRecord(DeviceExt, FileObject); 5650409b316STrevor Thompson 5660409b316STrevor Thompson // Update the parent directory index 5670409b316STrevor Thompson // Still TODO 5680409b316STrevor Thompson 5690409b316STrevor Thompson // Call NtfsOpenFile() 5700409b316STrevor Thompson 57158a13831STrevor Thompson return STATUS_CANNOT_MAKE; 572c2c66affSColin Finck } 573c2c66affSColin Finck } 574c2c66affSColin Finck 575c2c66affSColin Finck if (NT_SUCCESS(Status)) 576c2c66affSColin Finck { 577c2c66affSColin Finck Fcb->OpenHandleCount++; 578c2c66affSColin Finck DeviceExt->OpenHandleCount++; 579c2c66affSColin Finck } 580c2c66affSColin Finck 581c2c66affSColin Finck /* 582c2c66affSColin Finck * If the directory containing the file to open doesn't exist then 583c2c66affSColin Finck * fail immediately 584c2c66affSColin Finck */ 585c2c66affSColin Finck Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0; 586c2c66affSColin Finck 587c2c66affSColin Finck return Status; 588c2c66affSColin Finck } 589c2c66affSColin Finck 590c2c66affSColin Finck 591c2c66affSColin Finck NTSTATUS 592c2c66affSColin Finck NtfsCreate(PNTFS_IRP_CONTEXT IrpContext) 593c2c66affSColin Finck { 594c2c66affSColin Finck PDEVICE_EXTENSION DeviceExt; 595c2c66affSColin Finck NTSTATUS Status; 596c2c66affSColin Finck PDEVICE_OBJECT DeviceObject; 597c2c66affSColin Finck 598c2c66affSColin Finck DeviceObject = IrpContext->DeviceObject; 599c2c66affSColin Finck if (DeviceObject == NtfsGlobalData->DeviceObject) 600c2c66affSColin Finck { 601c2c66affSColin Finck /* DeviceObject represents FileSystem instead of logical volume */ 602c2c66affSColin Finck DPRINT("Opening file system\n"); 603c2c66affSColin Finck IrpContext->Irp->IoStatus.Information = FILE_OPENED; 604c2c66affSColin Finck return STATUS_SUCCESS; 605c2c66affSColin Finck } 606c2c66affSColin Finck 607c2c66affSColin Finck DeviceExt = DeviceObject->DeviceExtension; 608c2c66affSColin Finck 609c2c66affSColin Finck if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT)) 610c2c66affSColin Finck { 611c2c66affSColin Finck return NtfsMarkIrpContextForQueue(IrpContext); 612c2c66affSColin Finck } 613c2c66affSColin Finck 614c2c66affSColin Finck ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, 615c2c66affSColin Finck TRUE); 616c2c66affSColin Finck Status = NtfsCreateFile(DeviceObject, 617c2c66affSColin Finck IrpContext->Irp); 618c2c66affSColin Finck ExReleaseResourceLite(&DeviceExt->DirResource); 619c2c66affSColin Finck 620c2c66affSColin Finck return Status; 621c2c66affSColin Finck } 622c2c66affSColin Finck 6230409b316STrevor Thompson /** 6240409b316STrevor Thompson * @name NtfsCreateFileRecord() 6250409b316STrevor Thompson * @implemented 6260409b316STrevor Thompson * 6270409b316STrevor Thompson * Creates a file record and saves it to the MFT. 6280409b316STrevor Thompson * 6290409b316STrevor Thompson * @param DeviceExt 6300409b316STrevor Thompson * Points to the target disk's DEVICE_EXTENSION 6310409b316STrevor Thompson * 6320409b316STrevor Thompson * @param FileObject 6330409b316STrevor Thompson * Pointer to a FILE_OBJECT describing the file to be created 6340409b316STrevor Thompson * 6350409b316STrevor Thompson * @return 6360409b316STrevor Thompson * STATUS_SUCCESS on success. 6370409b316STrevor Thompson * STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record. 6380409b316STrevor Thompson */ 6390409b316STrevor Thompson NTSTATUS 6400409b316STrevor Thompson NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt, 6410409b316STrevor Thompson PFILE_OBJECT FileObject) 6420409b316STrevor Thompson { 6430409b316STrevor Thompson NTSTATUS Status = STATUS_SUCCESS; 6440409b316STrevor Thompson PFILE_RECORD_HEADER FileRecord; 6450409b316STrevor Thompson PNTFS_ATTR_RECORD NextAttribute; 6460409b316STrevor Thompson 6470409b316STrevor Thompson // allocate memory for file record 6480409b316STrevor Thompson FileRecord = ExAllocatePoolWithTag(NonPagedPool, 6490409b316STrevor Thompson DeviceExt->NtfsInfo.BytesPerFileRecord, 6500409b316STrevor Thompson TAG_NTFS); 6510409b316STrevor Thompson if (!FileRecord) 6520409b316STrevor Thompson { 6530409b316STrevor Thompson DPRINT1("ERROR: Unable to allocate memory for file record!\n"); 6540409b316STrevor Thompson return STATUS_INSUFFICIENT_RESOURCES; 6550409b316STrevor Thompson } 6560409b316STrevor Thompson 6570409b316STrevor Thompson RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord); 6580409b316STrevor Thompson 6590409b316STrevor Thompson FileRecord->Ntfs.Type = NRH_FILE_TYPE; 6600409b316STrevor Thompson 6610409b316STrevor Thompson // calculate USA offset and count 6620409b316STrevor Thompson FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG); 6630409b316STrevor Thompson 6640409b316STrevor Thompson // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses 6650409b316STrevor Thompson FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord; 6660409b316STrevor Thompson FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1; 6670409b316STrevor Thompson 6680409b316STrevor Thompson // setup other file record fields 6690409b316STrevor Thompson FileRecord->SequenceNumber = 1; 6700409b316STrevor Thompson FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount); 6710409b316STrevor Thompson FileRecord->AttributeOffset = ALIGN_UP_BY(FileRecord->AttributeOffset, 8); 6720409b316STrevor Thompson FileRecord->Flags = FRH_IN_USE; 6730409b316STrevor Thompson FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2; 6740409b316STrevor Thompson 6750409b316STrevor Thompson // find where the first attribute will be added 6760409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); 6770409b316STrevor Thompson 6780409b316STrevor Thompson // mark the (temporary) end of the file-record 6790409b316STrevor Thompson NextAttribute->Type = AttributeEnd; 6800409b316STrevor Thompson NextAttribute->Length = FILE_RECORD_END; 6810409b316STrevor Thompson 6820409b316STrevor Thompson // add first attribute, $STANDARD_INFORMATION 6830409b316STrevor Thompson AddStandardInformation(FileRecord, NextAttribute); 6840409b316STrevor Thompson 6850409b316STrevor Thompson // advance NextAttribute pointer to the next attribute 6860409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length); 6870409b316STrevor Thompson 6880409b316STrevor Thompson // Add the $FILE_NAME attribute 6890409b316STrevor Thompson AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject); 6900409b316STrevor Thompson 6910409b316STrevor Thompson // advance NextAttribute pointer to the next attribute 6920409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length); 6930409b316STrevor Thompson 6940409b316STrevor Thompson // add the $DATA attribute 6950409b316STrevor Thompson AddData(FileRecord, NextAttribute); 6960409b316STrevor Thompson 6970409b316STrevor Thompson // dump file record in memory (for debugging) 6980409b316STrevor Thompson NtfsDumpFileRecord(DeviceExt, FileRecord); 6990409b316STrevor Thompson 7000409b316STrevor Thompson // Now that we've built the file record in memory, we need to store it in the MFT. 7010409b316STrevor Thompson Status = AddNewMftEntry(FileRecord, DeviceExt); 7020409b316STrevor Thompson 7030409b316STrevor Thompson ExFreePoolWithTag(FileRecord, TAG_NTFS); 7040409b316STrevor Thompson 7050409b316STrevor Thompson return Status; 7060409b316STrevor Thompson } 7070409b316STrevor Thompson 708c2c66affSColin Finck /* EOF */ 709