[NTFS]
[reactos.git] / reactos / drivers / filesystems / ntfs / create.c
index 5db919b..a71c507 100644 (file)
@@ -46,6 +46,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 +84,79 @@ 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;
+}
+
 /*
  * FUNCTION: Opens a file
  */
@@ -98,13 +183,11 @@ NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
         Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject,
                                           FileName,
                                           &AbsFileName);
-        FileName = AbsFileName;
+        if (AbsFileName) FileName = AbsFileName;
         if (!NT_SUCCESS(Status))
         {
             return Status;
         }
-
-        return STATUS_UNSUCCESSFUL;
     }
 
     //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
@@ -169,6 +252,7 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
     PNTFS_FCB Fcb;
 //    PWSTR FileName;
     NTSTATUS Status;
+    UNICODE_STRING FullPath;
 
     DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, Irp);
 
@@ -195,6 +279,29 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
         return STATUS_ACCESS_DENIED;
     }
 
+    if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID)
+    {
+        ULONGLONG MFTId;
+
+        if (FileObject->FileName.Length != sizeof(ULONGLONG))
+            return STATUS_INVALID_PARAMETER;
+
+        MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK;
+        if (MFTId < 0xf)
+        {
+            UNIMPLEMENTED;
+            return STATUS_NOT_IMPLEMENTED;
+        }
+
+        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 */
     if (FileObject->FileName.Length == 0 &&
         (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
@@ -219,9 +326,14 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
 
     Status = NtfsOpenFile(DeviceExt,
                           FileObject,
-                          FileObject->FileName.Buffer,
+                          ((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))
     {
         if (RequestedDisposition == FILE_CREATE)
@@ -245,21 +357,38 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
             return STATUS_NOT_A_DIRECTORY;
         }
 
-        /* Properly handle reparse points:
-         * - likely overwrite FO name
-         * - return STATUS_REPARSE to IO manager
-         * - Do we have to attach reparse data to Irp->Tail.Overlay.AuxiliaryBuffer?
-         * See: http://www.osronline.com/showThread.cfm?link=6623
-         *
+        /*
          * If it is a reparse point & FILE_OPEN_REPARSE_POINT, then allow opening it
          * as a normal file.
+         * Otherwise, attempt to read reparse data and hand them to the Io manager
+         * with status reparse to force a reparse.
          */
         if (NtfsFCBIsReparsePoint(Fcb) &&
             ((RequestedOptions & FILE_OPEN_REPARSE_POINT) != FILE_OPEN_REPARSE_POINT))
         {
-            DPRINT1("Reparse point not handled!\n");
+            PREPARSE_DATA_BUFFER ReparseData = NULL;
+
+            Status = NtfsReadFCBAttribute(DeviceExt, Fcb,
+                                          AttributeReparsePoint, L"", 0,
+                                          (PVOID *)&Irp->Tail.Overlay.AuxiliaryBuffer);
+            if (NT_SUCCESS(Status))
+            {
+                ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
+                if (ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+                {
+                    Status = STATUS_REPARSE;
+                }
+                else
+                {
+                    Status = STATUS_NOT_IMPLEMENTED;
+                    ExFreePoolWithTag(ReparseData, TAG_NTFS);
+                }
+            }
+
+            Irp->IoStatus.Information = ((Status == STATUS_REPARSE) ? ReparseData->ReparseTag : 0);
+
             NtfsCloseFile(DeviceExt, FileObject);
-            return STATUS_NOT_IMPLEMENTED;
+            return Status;
         }
 
         /* HUGLY HACK: remain RO so far... */
@@ -290,43 +419,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;
 }