Author: pschweitzer
Date: Sun Dec 7 20:59:45 2014
New Revision: 65586
URL: http://svn.reactos.org/svn/reactos?rev=65586&view=rev
Log:
[NTFS]
- Implement NtfsReadFCBAttribute() which is responsible for reading an attribute from a file which is referenced by its FCB. It will first read the file record in the MFT and then read the attribute, if found.
- Use NtfsReadFCBAttribute() to implement support for reparse point in NtfsCreateFile(). Once a reparse point is found, we attempt to open its data. Given their layout, we directly hand them to the Io manager. Just make sure that we return something consistent on disk. Only handle IO_REPARSE_TAG_MOUNT_POINT so far.
Next question to answer is: what to do when a reparse point is encountered during path traversal?
Modified:
trunk/reactos/drivers/filesystems/ntfs/create.c
trunk/reactos/drivers/filesystems/ntfs/fcb.c
trunk/reactos/drivers/filesystems/ntfs/ntfs.h
Modified: trunk/reactos/drivers/filesystems/ntfs/create.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/c…
==============================================================================
--- trunk/reactos/drivers/filesystems/ntfs/create.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/ntfs/create.c [iso-8859-1] Sun Dec 7 20:59:45 2014
@@ -245,21 +245,43 @@
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");
- NtfsCloseFile(DeviceExt, FileObject);
- return STATUS_NOT_IMPLEMENTED;
+ if (Fcb->Entry.Extended.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ Status = NtfsReadFCBAttribute(DeviceExt, Fcb,
+ AttributeReparsePoint, L"", 0,
+ (PVOID *)&Irp->Tail.Overlay.AuxiliaryBuffer);
+ if (NT_SUCCESS(Status))
+ {
+ PREPARSE_DATA_BUFFER ReparseData;
+
+ ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
+ if (ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ Status = STATUS_REPARSE;
+ }
+ else
+ {
+ Status = STATUS_FILE_CORRUPT_ERROR;
+ ExFreePoolWithTag(ReparseData, TAG_NTFS);
+ }
+ }
+ }
+ else
+ {
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+
+ NtfsCloseFile(DeviceExt, FileObject);
+ return Status;
}
/* HUGLY HACK: remain RO so far... */
Modified: trunk/reactos/drivers/filesystems/ntfs/fcb.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/f…
==============================================================================
--- trunk/reactos/drivers/filesystems/ntfs/fcb.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/ntfs/fcb.c [iso-8859-1] Sun Dec 7 20:59:45 2014
@@ -646,4 +646,57 @@
return STATUS_SUCCESS;
}
+
+NTSTATUS
+NtfsReadFCBAttribute(PNTFS_VCB Vcb,
+ PNTFS_FCB pFCB,
+ ULONG Type,
+ PCWSTR Name,
+ ULONG NameLength,
+ PVOID * Data)
+{
+ NTSTATUS Status;
+ PFILE_RECORD_HEADER FileRecord;
+ PNTFS_ATTR_CONTEXT AttrCtxt;
+ ULONGLONG AttrLength;
+
+ FileRecord = ExAllocatePoolWithTag(NonPagedPool,
+ Vcb->NtfsInfo.BytesPerFileRecord,
+ TAG_NTFS);
+ if (FileRecord == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = ReadFileRecord(Vcb, NTFS_FILE_BITMAP, FileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ AttrLength = AttributeDataLength(&AttrCtxt->Record);
+ *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS);
+ if (*Data == NULL)
+ {
+ ReleaseAttributeContext(AttrCtxt);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
+
+ ReleaseAttributeContext(AttrCtxt);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+
+ return STATUS_SUCCESS;
+}
+
/* EOF */
Modified: trunk/reactos/drivers/filesystems/ntfs/ntfs.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/n…
==============================================================================
--- trunk/reactos/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] Sun Dec 7 20:59:45 2014
@@ -615,6 +615,14 @@
PNTFS_FCB *pFCB,
const PWSTR pFileName);
+NTSTATUS
+NtfsReadFCBAttribute(PNTFS_VCB Vcb,
+ PNTFS_FCB pFCB,
+ ULONG Type,
+ PCWSTR Name,
+ ULONG NameLength,
+ PVOID * Data);
+
/* finfo.c */
Author: pschweitzer
Date: Sun Dec 7 17:59:58 2014
New Revision: 65584
URL: http://svn.reactos.org/svn/reactos?rev=65584&view=rev
Log:
[NTOSKRNL]
Implement support for (some) reparse points in Io manager. Ob should be already fine.
- Implement the IopDoNameTransmogrify() function. This one is responsible for checking the correct data for the reparse point and to update the path name in the file object. It will also free the memory buffer allocated by the driver to communicate the reparse information.
- Fix the support for reparse points in IopCompleteRequest(). If we receive reparse status + reparse tag we know, we call IopDoNameTransmogrify() to update file objet.
- Fix the support for reparse points in IopParseDevice() (oh! you again? :-)). When we complete the IRP ourselves, act as in IopCompleteRequest(). Then, we properly update objects manipulated by Io for the create request and we return STATUS_REPARSE so that Ob can update and recall us afterwards so that we complete.
Some parts are left unimplemented when it comes to reparse tags which are not IO_REPARSE_TAG_MOUNT_POINT. But still less than previously ;-).
Modified:
trunk/reactos/ntoskrnl/io/iomgr/file.c
trunk/reactos/ntoskrnl/io/iomgr/irp.c
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/file.c?r…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/file.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/file.c [iso-8859-1] Sun Dec 7 17:59:58 2014
@@ -160,6 +160,107 @@
InterlockedIncrement(&DeviceObject->ReferenceCount);
return STATUS_SUCCESS;
}
+}
+
+VOID
+NTAPI
+IopDoNameTransmogrify(IN PIRP Irp,
+ IN PFILE_OBJECT FileObject,
+ IN PREPARSE_DATA_BUFFER DataBuffer)
+{
+ PWSTR Buffer;
+ USHORT Length;
+ USHORT RequiredLength;
+ PWSTR NewBuffer;
+
+ PAGED_CODE();
+
+ ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
+ ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+ ASSERT(DataBuffer != NULL);
+ ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ /* First of all, validate data */
+ if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
+ (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+ DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
+ {
+ Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ /* Everything went right */
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* Compute buffer & length */
+ Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
+ DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
+ Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
+
+ /* Check we don't overflow */
+ if ((MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
+ {
+ Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+ }
+ else
+ {
+ /* Compute how much mem we'll need */
+ RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
+
+ /* Check if FileObject can already hold what we need */
+ if (FileObject->FileName.MaximumLength >= RequiredLength)
+ {
+ NewBuffer = FileObject->FileName.Buffer;
+ }
+ else
+ {
+ /* Allocate otherwise */
+ NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
+ if (NewBuffer == NULL)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ }
+ }
+
+ /* Everything went right */
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* Copy reserved */
+ if (DataBuffer->Reserved)
+ {
+ RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
+ (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
+ DataBuffer->Reserved);
+ }
+
+ /* Then, buffer */
+ if (Length)
+ {
+ RtlCopyMemory(NewBuffer, Buffer, Length);
+ }
+
+ /* And finally replace buffer if new one was allocated */
+ FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
+ if (NewBuffer != FileObject->FileName.Buffer)
+ {
+ if (FileObject->FileName.Buffer)
+ {
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ }
+
+ FileObject->FileName.Buffer = NewBuffer;
+ FileObject->FileName.MaximumLength = RequiredLength;
+ FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
+ }
+ }
+
+ /* We don't need them anymore - it was allocated by the driver */
+ ExFreePool(DataBuffer);
}
NTSTATUS
@@ -206,6 +307,23 @@
/* Validate the open packet */
if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
+ /* Valide reparse point in case we traversed a mountpoint */
+ if (OpenPacket->TraversedMountPoint)
+ {
+ /* This is a reparse point we understand */
+ ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
+
+ /* Make sure we're dealing with correct DO */
+ if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
+ {
+ OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
+ return STATUS_IO_REPARSE_DATA_INVALID;
+ }
+ }
+
/* Check if we have a related file object */
if (OpenPacket->RelatedFileObject)
{
@@ -404,6 +522,7 @@
/* Check if we can simply use a dummy file */
UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
+#if 1
/* FIXME: Small hack still exists, have to check why...
* This is triggered multiple times by usetup and then once per boot.
*/
@@ -424,6 +543,7 @@
WRITE_DAC));
DirectOpen = TRUE;
}
+#endif
/* Check if this is a direct open */
if (!(RemainingName->Length) &&
@@ -482,6 +602,12 @@
/* Get the attached device */
DeviceObject = IoGetAttachedDevice(DeviceObject);
}
+ }
+
+ /* If we traversed a mount point, reset the information */
+ if (OpenPacket->TraversedMountPoint)
+ {
+ OpenPacket->TraversedMountPoint = FALSE;
}
/* Check if this is a secure FSD */
@@ -740,6 +866,26 @@
ASSERT(!Irp->PendingReturned);
ASSERT(!Irp->MdlAddress);
+ /* Handle name change if required */
+ if (Status == STATUS_REPARSE)
+ {
+ /* Check this is a mount point */
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ PREPARSE_DATA_BUFFER ReparseData;
+
+ /* Reparse point attributes were passed by the driver in the auxiliary buffer */
+ ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+ ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
+
+ ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ IopDoNameTransmogrify(Irp, FileObject, ReparseData);
+ }
+ }
+
/* Completion happens at APC_LEVEL */
KeRaiseIrql(APC_LEVEL, &OldIrql);
@@ -805,7 +951,90 @@
}
else if (Status == STATUS_REPARSE)
{
- /* FIXME: We don't handle this at all! */
+ if (OpenPacket->Information == IO_REPARSE ||
+ OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
+ if (CompleteName->MaximumLength < FileObject->FileName.Length)
+ {
+ PWSTR NewCompleteName;
+
+ /* Allocate a new buffer for the string */
+ NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
+ if (NewCompleteName == NULL)
+ {
+ OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Release the old one */
+ if (CompleteName->Buffer != NULL)
+ {
+ ExFreePoolWithTag(CompleteName->Buffer, TAG_IO_NAME);
+ }
+
+ /* And setup the new one */
+ CompleteName->Buffer = NewCompleteName;
+ CompleteName->MaximumLength = FileObject->FileName.Length;
+ }
+
+ /* Copy our new complete name */
+ RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
+
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ OpenPacket->RelatedFileObject = NULL;
+ }
+ }
+
+ /* Check if we have a name */
+ if (FileObject->FileName.Length)
+ {
+ /* Free it */
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ FileObject->FileName.Length = 0;
+ }
+
+ /* Clear its device object */
+ FileObject->DeviceObject = NULL;
+
+ /* Clear the file object in the open packet */
+ OpenPacket->FileObject = NULL;
+
+ /* Dereference the file object */
+ if (!UseDummyFile) ObDereferenceObject(FileObject);
+
+ /* Dereference the device object */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+
+ /* Unless the driver cancelled the open, dereference the VPB */
+ if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
+
+ if (OpenPacket->Information != IO_REMOUNT)
+ {
+ OpenPacket->RelatedFileObject = NULL;
+
+ /* Inform we traversed a mount point for later attempt */
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ OpenPacket->TraversedMountPoint = 1;
+ }
+
+ /* In case we override checks, but got this on volume open, fail hard */
+ if (OpenPacket->Override)
+ {
+ KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
+ (ULONG_PTR)OriginalDeviceObject,
+ (ULONG_PTR)DeviceObject,
+ (ULONG_PTR)CompleteName,
+ OpenPacket->Information);
+ }
+
+ /* Return to IO/OB so that information can be upgraded */
+ return STATUS_REPARSE;
+ }
+
+ /* FIXME: At that point, we should loop again and reattempt an opening */
ASSERT(FALSE);
}
Modified: trunk/reactos/ntoskrnl/io/iomgr/irp.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/irp.c?re…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/irp.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/irp.c [iso-8859-1] Sun Dec 7 17:59:58 2014
@@ -264,9 +264,15 @@
if ((Irp->IoStatus.Status == STATUS_REPARSE) &&
(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT))
{
- /* We should never get this yet */
- UNIMPLEMENTED_DBGBREAK("Reparse support not yet present!\n");
- return;
+ PREPARSE_DATA_BUFFER ReparseData;
+
+ ReparseData = (PREPARSE_DATA_BUFFER)*SystemArgument2;
+
+ ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ IopDoNameTransmogrify(Irp, FileObject, ReparseData);
}
}
Author: aandrejevic
Date: Sun Dec 7 17:53:08 2014
New Revision: 65583
URL: http://svn.reactos.org/svn/reactos?rev=65583&view=rev
Log:
[SHELL32:ICONS]
Replace the old "My Computer" icon with a new one.
New icon by: Ismael Ferreras Morezuelas.
CORE-8890 #resolve #comment Committed in revision r65583. Thanks!
Modified:
trunk/reactos/dll/win32/shell32/res/icons/16.ico
Modified: trunk/reactos/dll/win32/shell32/res/icons/16.ico
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/res/icon…
==============================================================================
Binary files - no diff available.