[NTFS]
[reactos.git] / reactos / drivers / filesystems / ntfs / create.c
index ac9920e..4d2c9fc 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
+static PCWSTR MftIdToName[] = {
+    L"$MFT",
+    L"$MFTMirr",
+    L"$LogFile",
+    L"$Volume",
+    L"AttrDef",
+    L".",
+    L"$Bitmap",
+    L"$Boot",
+    L"$BadClus",
+    L"$Quota",
+    L"$UpCase",
+    L"$Extended",
+};
+
 /* FUNCTIONS ****************************************************************/
 
 static
@@ -46,6 +61,18 @@ NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject,
     Fcb = pFileObject->FsContext;
     ASSERT(Fcb);
 
+    if (Fcb->Flags & FCB_IS_VOLUME)
+    {
+        /* This is likely to be an opening by ID, return ourselves */
+        if (pRelativeFileName[0] == L'\\')
+        {
+            *pAbsoluteFilename = NULL;
+            return STATUS_SUCCESS;
+        }
+
+        return STATUS_INVALID_PARAMETER;
+    }
+
     /* verify related object is a directory and target name
        don't start with \. */
     if (NtfsFCBIsDirectory(Fcb) == FALSE ||
@@ -72,6 +99,145 @@ NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject,
 }
 
 
+static
+NTSTATUS
+NtfsMoonWalkID(PDEVICE_EXTENSION DeviceExt,
+               ULONGLONG Id,
+               PUNICODE_STRING OutPath)
+{
+    NTSTATUS Status;
+    PFILE_RECORD_HEADER MftRecord;
+    PFILENAME_ATTRIBUTE FileName;
+    WCHAR FullPath[MAX_PATH];
+    ULONG WritePosition = MAX_PATH - 1;
+
+    DPRINT1("NtfsMoonWalkID(%p, %I64x, %p)\n", DeviceExt, Id, OutPath);
+
+    RtlZeroMemory(FullPath, sizeof(FullPath));
+    MftRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                      DeviceExt->NtfsInfo.BytesPerFileRecord,
+                                      TAG_NTFS);
+    if (MftRecord == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    while (TRUE)
+    {
+        Status = ReadFileRecord(DeviceExt, Id, MftRecord);
+        if (!NT_SUCCESS(Status))
+            break;
+
+        ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
+        if (!(MftRecord->Flags & FRH_IN_USE))
+        {
+            Status = STATUS_OBJECT_PATH_NOT_FOUND;
+            break;
+        }
+
+        FileName = GetBestFileNameFromRecord(MftRecord);
+        if (FileName == NULL)
+        {
+            DPRINT1("$FILE_NAME attribute not found for %I64x\n", Id);
+            Status = STATUS_OBJECT_PATH_NOT_FOUND;
+            break;
+        }
+
+        WritePosition -= FileName->NameLength;
+        ASSERT(WritePosition < MAX_PATH);
+        RtlCopyMemory(FullPath + WritePosition, FileName->Name, FileName->NameLength * sizeof(WCHAR));
+        WritePosition -= 1;
+        ASSERT(WritePosition < MAX_PATH);
+        FullPath[WritePosition] = L'\\';
+
+        Id = FileName->DirectoryFileReferenceNumber & NTFS_MFT_MASK;
+        if (Id == NTFS_FILE_ROOT)
+            break;
+    }
+
+    ExFreePoolWithTag(MftRecord, TAG_NTFS);
+
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    OutPath->Length = (MAX_PATH - WritePosition - 1) * sizeof(WCHAR);
+    OutPath->MaximumLength = (MAX_PATH - WritePosition) * sizeof(WCHAR);
+    OutPath->Buffer = ExAllocatePoolWithTag(NonPagedPool, OutPath->MaximumLength, TAG_NTFS);
+    if (OutPath->Buffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    RtlCopyMemory(OutPath->Buffer, FullPath + WritePosition, OutPath->MaximumLength);
+
+    return Status;
+}
+
+static
+NTSTATUS
+NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt,
+                 PFILE_OBJECT FileObject,
+                 ULONGLONG MftId,
+                 PNTFS_FCB * FoundFCB)
+{
+    NTSTATUS Status;
+    PNTFS_FCB FCB;
+    PFILE_RECORD_HEADER MftRecord;
+
+    DPRINT1("NtfsOpenFileById(%p, %p, %I64x, %p)\n", DeviceExt, FileObject, MftId, FoundFCB);
+
+    ASSERT(MftId < 0x10);
+    if (MftId > 0xb) /* No entries are used yet beyond this */
+    {
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
+
+    MftRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                      DeviceExt->NtfsInfo.BytesPerFileRecord,
+                                      TAG_NTFS);
+    if (MftRecord == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = ReadFileRecord(DeviceExt, MftId, MftRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        return Status;
+    }
+
+    if (!(MftRecord->Flags & FRH_IN_USE))
+    {
+        ExFreePoolWithTag(MftRecord, TAG_NTFS);
+        return STATUS_OBJECT_PATH_NOT_FOUND;
+    }
+
+    FCB = NtfsGrabFCBFromTable(DeviceExt, MftIdToName[MftId]);
+    if (FCB == NULL)
+    {
+        UNICODE_STRING Name;
+
+        RtlInitUnicodeString(&Name, MftIdToName[MftId]);
+        Status = NtfsMakeFCBFromDirEntry(DeviceExt, NULL, &Name, MftRecord, MftId, &FCB);
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePoolWithTag(MftRecord, TAG_NTFS);
+            return Status;
+        }
+    }
+
+    ASSERT(FCB != NULL);
+
+    ExFreePoolWithTag(MftRecord, TAG_NTFS);
+
+    Status = NtfsAttachFCBToFileObject(DeviceExt,
+                                       FCB,
+                                       FileObject);
+    *FoundFCB = FCB;
+
+    return Status;
+}
+
 /*
  * FUNCTION: Opens a file
  */
@@ -80,7 +246,6 @@ NTSTATUS
 NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
              PFILE_OBJECT FileObject,
              PWSTR FileName,
-             BOOLEAN OpenById,
              PNTFS_FCB * FoundFCB)
 {
     PNTFS_FCB ParentFcb;
@@ -88,81 +253,53 @@ NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
     NTSTATUS Status;
     PWSTR AbsFileName = NULL;
 
-    DPRINT1("NtfsOpenFile(%p, %p, %S, %u, %p)\n", DeviceExt, FileObject, (!OpenById ? FileName : NULL), OpenById, FoundFCB);
+    DPRINT1("NtfsOpenFile(%p, %p, %S, %p)\n", DeviceExt, FileObject, FileName, FoundFCB);
 
     *FoundFCB = NULL;
 
-    if (OpenById)
+    if (FileObject->RelatedFileObject)
     {
-        ULONGLONG Id = (*(PULONGLONG)FileName) & NTFS_MFT_MASK;
+        DPRINT("Converting relative filename to absolute filename\n");
 
-        DPRINT1("Will attempt to open by id: %I64x\n", Id);
-
-        Fcb = NtfsGrabFCBFromTableById(DeviceExt,
-                                       Id);
-        if (Fcb == NULL)
+        Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject,
+                                          FileName,
+                                          &AbsFileName);
+        if (AbsFileName) FileName = AbsFileName;
+        if (!NT_SUCCESS(Status))
         {
-            Status = NtfsGetFCBForFileById(DeviceExt,
-                                           &Fcb,
-                                           Id);
-            if (!NT_SUCCESS (Status))
-            {
-                DPRINT("Could not make a new FCB, status: %x\n", Status);
-
-                return Status;
-            }
-
-            Fcb->Flags |= FCB_IS_OPEN_BY_ID;
+            return Status;
         }
     }
-    else
-    {
-        if (FileObject->RelatedFileObject)
-        {
-            DPRINT("Converting relative filename to absolute filename\n");
 
-            Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject,
-                                              FileName,
-                                              &AbsFileName);
-            FileName = AbsFileName;
-            if (!NT_SUCCESS(Status))
-            {
-                return Status;
-            }
-
-            return STATUS_UNSUCCESSFUL;
-        }
+    //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
 
-        //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
+    DPRINT("PathName to open: %S\n", FileName);
 
-        DPRINT("PathName to open: %S\n", FileName);
-
-        /*  try first to find an existing FCB in memory  */
-        DPRINT("Checking for existing FCB in memory\n");
-        Fcb = NtfsGrabFCBFromTable(DeviceExt,
+    /*  try first to find an existing FCB in memory  */
+    DPRINT("Checking for existing FCB in memory\n");
+    Fcb = NtfsGrabFCBFromTable(DeviceExt,
+                               FileName);
+    if (Fcb == NULL)
+    {
+        DPRINT("No existing FCB found, making a new one if file exists.\n");
+        Status = NtfsGetFCBForFile(DeviceExt,
+                                   &ParentFcb,
+                                   &Fcb,
                                    FileName);
-        if (Fcb == NULL)
+        if (ParentFcb != NULL)
         {
-            DPRINT("No existing FCB found, making a new one if file exists.\n");
-            Status = NtfsGetFCBForFile(DeviceExt,
-                                       &ParentFcb,
-                                       &Fcb,
-                                       FileName);
-            if (ParentFcb != NULL)
-            {
-                NtfsReleaseFCB(DeviceExt,
-                               ParentFcb);
-            }
+            NtfsReleaseFCB(DeviceExt,
+                           ParentFcb);
+        }
 
-            if (!NT_SUCCESS (Status))
-            {
-                DPRINT("Could not make a new FCB, status: %x\n", Status);
+        if (!NT_SUCCESS (Status))
+        {
+            DPRINT("Could not make a new FCB, status: %x\n", Status);
 
-                if (AbsFileName)
-                    ExFreePool(AbsFileName);
+            if (AbsFileName)
+                ExFreePool(AbsFileName);
 
-                return Status;
-            }
+            return Status;
         }
     }
 
@@ -193,9 +330,10 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
     PFILE_OBJECT FileObject;
     ULONG RequestedDisposition;
     ULONG RequestedOptions;
-    PNTFS_FCB Fcb;
+    PNTFS_FCB Fcb = NULL;
 //    PWSTR FileName;
     NTSTATUS Status;
+    UNICODE_STRING FullPath;
 
     DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, Irp);
 
@@ -213,12 +351,6 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
         return STATUS_INVALID_PARAMETER;
     }
 
-    if (RequestedOptions & FILE_OPEN_BY_FILE_ID)
-    {
-        UNIMPLEMENTED;
-        return STATUS_NOT_IMPLEMENTED;
-    }
-
     FileObject = Stack->FileObject;
 
     if (RequestedDisposition == FILE_CREATE ||
@@ -228,10 +360,29 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
         return STATUS_ACCESS_DENIED;
     }
 
-    if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID &&
-        FileObject->FileName.Length != sizeof(ULONGLONG))
+    if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID)
     {
-        return STATUS_INVALID_PARAMETER;
+        ULONGLONG MFTId;
+
+        if (FileObject->FileName.Length != sizeof(ULONGLONG))
+            return STATUS_INVALID_PARAMETER;
+
+        MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK;
+        if (MFTId < 0x10)
+        {
+            Status = NtfsOpenFileById(DeviceExt, FileObject, MFTId, &Fcb);
+        }
+        else
+        {
+            Status = NtfsMoonWalkID(DeviceExt, MFTId, &FullPath);
+        }
+
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
+        DPRINT1("Open by ID: %I64x -> %wZ\n", (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK, &FullPath);
     }
 
     /* This a open operation for the volume itself */
@@ -256,11 +407,18 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
         return STATUS_SUCCESS;
     }
 
-    Status = NtfsOpenFile(DeviceExt,
-                          FileObject,
-                          FileObject->FileName.Buffer,
-                          ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID),
-                          &Fcb);
+    if (Fcb == NULL)
+    {
+        Status = NtfsOpenFile(DeviceExt,
+                              FileObject,
+                              ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? FullPath.Buffer : FileObject->FileName.Buffer),
+                              &Fcb);
+
+        if (RequestedOptions & FILE_OPEN_BY_FILE_ID)
+        {
+            ExFreePoolWithTag(FullPath.Buffer, TAG_NTFS);
+        }
+    }
 
     if (NT_SUCCESS(Status))
     {
@@ -347,43 +505,39 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
      * fail immediately
      */
     Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0;
-    Irp->IoStatus.Status = Status;
 
     return Status;
 }
 
 
 NTSTATUS
-NTAPI
-NtfsFsdCreate(PDEVICE_OBJECT DeviceObject,
-              PIRP Irp)
+NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)
 {
     PDEVICE_EXTENSION DeviceExt;
     NTSTATUS Status;
+    PDEVICE_OBJECT DeviceObject;
 
+    DeviceObject = IrpContext->DeviceObject;
     if (DeviceObject == NtfsGlobalData->DeviceObject)
     {
         /* DeviceObject represents FileSystem instead of logical volume */
         DPRINT("Opening file system\n");
-        Irp->IoStatus.Information = FILE_OPENED;
-        Status = STATUS_SUCCESS;
-        goto ByeBye;
+        IrpContext->Irp->IoStatus.Information = FILE_OPENED;
+        return STATUS_SUCCESS;
     }
 
     DeviceExt = DeviceObject->DeviceExtension;
 
-    FsRtlEnterFileSystem();
+    if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
+    {
+        return NtfsMarkIrpContextForQueue(IrpContext);
+    }
+
     ExAcquireResourceExclusiveLite(&DeviceExt->DirResource,
                                    TRUE);
     Status = NtfsCreateFile(DeviceObject,
-                            Irp);
+                            IrpContext->Irp);
     ExReleaseResourceLite(&DeviceExt->DirResource);
-    FsRtlExitFileSystem();
-
-ByeBye:
-    Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp,
-                      NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
 
     return Status;
 }