Author: ion Date: Wed May 24 06:45:06 2006 New Revision: 22000
URL: http://svn.reactos.ru/svn/reactos?rev=22000&view=rev Log: - Fix Symbolic Link implementation: - Use OBJECT_SYMBOLIC_LINK structure as used by Windows NT (and added the structure to the NDK) - Changed code to use the new names in the structure - Only free the symlink's name if it has one, to avoid a bugcheck. - Optimize parsing: if the new name is actually shorter then the target name, then don't allocate from pool, but re-use the buffer. This improves symlink parsing speed. Also fix a bug which made it depend on the incorrect implementation of NtCreateSymbolicLinkObject - Re-align the link target maximum length in NtCreateSymbolicLinkObject if it's odd, and fail if the length is odd, smaller then the maximum, or if the maximum is zero. - Originally allocate the symlink name in Paged Pool. - Initialize new members of the structure. - Fail in no-memory case, instead of continuing. - Properly probe the LinkTarget in NtQuerySymbolicLinkObject. - Properly handle which length is chosen for the copy and for the return in NtQuerySymbolicObject. - Lock the symbolic link object type while querying it. Eventually many more parts of Ob need to do this kind of locking. - SymLinkTest now only gives 2 failures. - Fix some NDK bugs
Modified: trunk/reactos/include/ndk/exfuncs.h trunk/reactos/include/ndk/obtypes.h trunk/reactos/include/ndk/psfuncs.h trunk/reactos/include/ndk/rtltypes.h trunk/reactos/ntoskrnl/include/internal/ob.h trunk/reactos/ntoskrnl/ob/ntobj.c trunk/reactos/ntoskrnl/ob/symlink.c
Modified: trunk/reactos/include/ndk/exfuncs.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/include/ndk/exfuncs.h?rev=22... ============================================================================== --- trunk/reactos/include/ndk/exfuncs.h (original) +++ trunk/reactos/include/ndk/exfuncs.h Wed May 24 06:45:06 2006 @@ -859,7 +859,6 @@ );
NTSYSAPI -NTSYSAPI NTSTATUS NTAPI ZwSetEvent(
Modified: trunk/reactos/include/ndk/obtypes.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/include/ndk/obtypes.h?rev=22... ============================================================================== --- trunk/reactos/include/ndk/obtypes.h (original) +++ trunk/reactos/include/ndk/obtypes.h Wed May 24 06:45:06 2006 @@ -384,15 +384,29 @@ { struct _OBJECT_DIRECTORY_ENTRY *ChainLink; PVOID Object; +#if (NTDDI_VERSION >= NTDDI_WS03) ULONG HashValue; +#endif } OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
typedef struct _OBJECT_DIRECTORY { struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[NUMBER_HASH_BUCKETS]; - struct _EX_PUSH_LOCK *Lock; +#if (NTDDI_VERSION < NTDDI_WINXP) + PERESOURCE Lock; +#elif (NTDDI_VERSION >= NTDDI_WINXP) + EX_PUSH_LOCK Lock; +#endif +#if (NTDDI_VERSION < NTDDI_WINXP) + BOOLEAN CurrentEntryValid; +#else struct _DEVICE_MAP *DeviceMap; +#endif ULONG SessionId; +#if (NTDDI_VERSION == NTDDI_WINXP) + USHORT Reserved; + USHORT SymbolicLinkUsageCount; +#endif } OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
// @@ -408,6 +422,18 @@ } DEVICE_MAP, *PDEVICE_MAP;
// +// Symbolic Link Object +// +typedef struct _OBJECT_SYMBOLIC_LINK +{ + LARGE_INTEGER CreationTime; + UNICODE_STRING LinkTarget; + UNICODE_STRING LinkTargetRemaining; + PVOID LinkTargetObject; + ULONG DosDeviceDriveIndex; +} OBJECT_SYMBOLIC_LINK, *POBJECT_SYMBOLIC_LINK; + +// // Kernel Exports // extern POBJECT_TYPE NTSYSAPI ObDirectoryType;
Modified: trunk/reactos/include/ndk/psfuncs.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/include/ndk/psfuncs.h?rev=22... ============================================================================== --- trunk/reactos/include/ndk/psfuncs.h (original) +++ trunk/reactos/include/ndk/psfuncs.h Wed May 24 06:45:06 2006 @@ -298,7 +298,6 @@ );
NTSYSCALLAPI -NTSYSCALLAPI NTSTATUS NTAPI NtSetInformationThread(
Modified: trunk/reactos/include/ndk/rtltypes.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/include/ndk/rtltypes.h?rev=2... ============================================================================== --- trunk/reactos/include/ndk/rtltypes.h (original) +++ trunk/reactos/include/ndk/rtltypes.h Wed May 24 06:45:06 2006 @@ -171,6 +171,42 @@ #define NLS_MB_CODE_PAGE_TAG NlsMbCodePageTag #define NLS_MB_OEM_CODE_PAGE_TAG NlsMbOemCodePageTag #define NLS_OEM_LEAD_BYTE_INFO NlsOemLeadByteInfo + +// +// C++ CONST casting +// +#if defined(__cplusplus) +#define RTL_CONST_CAST(type) const_cast<type> +#else +#define RTL_CONST_CAST(type) (type) +#endif + +// +// Constant String Macro +// +#define RTL_CONSTANT_STRING(__SOURCE_STRING__) \ +{ \ + sizeof(__SOURCE_STRING__) - sizeof((__SOURCE_STRING__)[0]), \ + sizeof(__SOURCE_STRING__), \ + (__SOURCE_STRING__) \ +} + +// +// Constant Object Attributes Macro +// +#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) \ +{ \ + sizeof(OBJECT_ATTRIBUTES), \ + NULL, \ + RTL_CONST_CAST(PUNICODE_STRING)(n), \ + a, \ + NULL, \ + NULL \ +} + +#define RTL_INIT_OBJECT_ATTRIBUTES(n, a) \ + RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) + #else // // Message Resource Flag
Modified: trunk/reactos/ntoskrnl/include/internal/ob.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/ntoskrnl/include/internal/ob... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ob.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ob.h Wed May 24 06:45:06 2006 @@ -22,14 +22,6 @@ LIST_ENTRY head; KSPIN_LOCK Lock; } DIRECTORY_OBJECT, *PDIRECTORY_OBJECT; - -typedef struct _SYMLINK_OBJECT -{ - CSHORT Type; - CSHORT Size; - UNICODE_STRING TargetName; - LARGE_INTEGER CreateTime; -} SYMLINK_OBJECT, *PSYMLINK_OBJECT;
typedef struct _ROS_OBJECT_HEADER {
Modified: trunk/reactos/ntoskrnl/ob/ntobj.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/ntoskrnl/ob/ntobj.c?rev=2200... ============================================================================== --- trunk/reactos/ntoskrnl/ob/ntobj.c (original) +++ trunk/reactos/ntoskrnl/ob/ntobj.c Wed May 24 06:45:06 2006 @@ -210,7 +210,7 @@ if (ObjectHeader->Type == ObSymbolicLinkType) { BasicInfo->CreateTime.QuadPart = - ((PSYMLINK_OBJECT)Object)->CreateTime.QuadPart; + ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart; } else {
Modified: trunk/reactos/ntoskrnl/ob/symlink.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/ntoskrnl/ob/symlink.c?rev=22... ============================================================================== --- trunk/reactos/ntoskrnl/ob/symlink.c (original) +++ trunk/reactos/ntoskrnl/ob/symlink.c Wed May 24 06:45:06 2006 @@ -48,8 +48,15 @@ NTAPI ObpDeleteSymbolicLink(PVOID ObjectBody) { - PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT)ObjectBody; - ExFreePool(SymlinkObject->TargetName.Buffer); + POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody; + + /* Make sure that the symbolic link has a name */ + if (SymlinkObject->LinkTarget.Buffer) + { + /* Free the name */ + ExFreePool(SymlinkObject->LinkTarget.Buffer); + SymlinkObject->LinkTarget.Buffer = NULL; + } }
/*++ @@ -85,10 +92,10 @@ PWSTR * RemainingPath, ULONG Attributes) { - PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT) Object; - UNICODE_STRING TargetPath; - - DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath); + POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)Object; + PUNICODE_STRING TargetPath; + PWSTR NewTargetPath; + ULONG LengthUsed, MaximumLength, RemainLength;
/* * Stop parsing if the entire path has been parsed and @@ -97,33 +104,51 @@ if (((*RemainingPath == NULL) || (**RemainingPath == 0)) && (Attributes & OBJ_OPENLINK)) { - DPRINT("Parsing stopped!\n"); *NextObject = NULL; return(STATUS_SUCCESS); }
- /* Build the expanded path */ - TargetPath.MaximumLength = SymlinkObject->TargetName.Length + - sizeof(WCHAR); - if (RemainingPath && *RemainingPath) - { - TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR)); - } - TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR); - TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, - TargetPath.MaximumLength, + /* Set the target path and length */ + TargetPath = &SymlinkObject->LinkTarget; + RemainLength = *RemainingPath ? wcslen(*RemainingPath) * sizeof(WCHAR) : 0; + LengthUsed = TargetPath->Length + RemainLength; + + /* Optimization: check if the new name is shorter */ + if (FullPath->MaximumLength <= LengthUsed) + { + /* It's not, allocate a new one */ + MaximumLength = LengthUsed + sizeof(WCHAR); + NewTargetPath = ExAllocatePoolWithTag(NonPagedPool, + MaximumLength, TAG_SYMLINK_TTARGET); - wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer); - if (RemainingPath && *RemainingPath) - { - wcscat(TargetPath.Buffer, *RemainingPath); - } - - /* Transfer target path buffer into FullPath */ - ExFreePool(FullPath->Buffer); - FullPath->Length = TargetPath.Length; - FullPath->MaximumLength = TargetPath.MaximumLength; - FullPath->Buffer = TargetPath.Buffer; + } + else + { + /* It is! Reuse the name... */ + MaximumLength = FullPath->MaximumLength; + NewTargetPath = FullPath->Buffer; + } + + /* Make sure we have a length */ + if (RemainLength) + { + /* Copy the new path */ + RtlMoveMemory((PVOID)((ULONG_PTR)NewTargetPath + TargetPath->Length), + *RemainingPath, + RemainLength); + } + + /* Copy the target path and null-terminate it */ + RtlMoveMemory(NewTargetPath, TargetPath->Buffer, TargetPath->Length); + NewTargetPath[LengthUsed / sizeof(WCHAR)] = UNICODE_NULL; + + /* If the optimization didn't work, free the old buffer */ + if (NewTargetPath != FullPath->Buffer) ExFreePool(FullPath->Buffer); + + /* Update the path values */ + FullPath->Length = LengthUsed; + FullPath->MaximumLength = MaximumLength; + FullPath->Buffer = NewTargetPath;
/* Reinitialize RemainingPath for reparsing */ *RemainingPath = FullPath->Buffer; @@ -152,13 +177,11 @@ UNICODE_STRING Name; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
- DPRINT("Creating SymLink Object Type\n"); - /* Initialize the Directory type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"SymbolicLink"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); - ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SYMLINK_OBJECT); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_SYMBOLIC_LINK); ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS; @@ -201,72 +224,99 @@ IN PUNICODE_STRING LinkTarget) { HANDLE hLink; - PSYMLINK_OBJECT SymbolicLink; + POBJECT_SYMBOLIC_LINK SymbolicLink; UNICODE_STRING CapturedLinkTarget; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE();
- DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul" - ", ObjectAttributes %p, LinkTarget %wZ)\n", - LinkHandle, - DesiredAccess, - ObjectAttributes, - LinkTarget); - + /* Check if we need to probe parameters */ if(PreviousMode != KernelMode) { _SEH_TRY { + /* Probe the target */ + ProbeForRead(LinkTarget, sizeof(UNICODE_STRING), sizeof(WCHAR)); + CapturedLinkTarget = *LinkTarget; + ProbeForRead(CapturedLinkTarget.Buffer, + CapturedLinkTarget.MaximumLength, + sizeof(WCHAR)); + + /* Probe the return handle */ ProbeForWriteHandle(LinkHandle); } _SEH_HANDLE { + /* Exception, get the error code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
- if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = ProbeAndCaptureUnicodeString(&CapturedLinkTarget, - PreviousMode, - LinkTarget); - if(!NT_SUCCESS(Status)) - { - DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n"); - return Status; - } - + /* Probing failed, return the error code */ + if(!NT_SUCCESS(Status)) return Status; + } + else + { + /* No need to capture */ + CapturedLinkTarget = *LinkTarget; + } + + /* Check if the maximum length is odd */ + if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR)) + { + /* Round it down */ + CapturedLinkTarget.MaximumLength = + ALIGN_DOWN(CapturedLinkTarget.MaximumLength, WCHAR); + } + + /* Fail if the length is odd, or if the maximum is smaller or 0 */ + if ((CapturedLinkTarget.Length % sizeof(WCHAR)) || + (CapturedLinkTarget.MaximumLength < CapturedLinkTarget.Length) || + !(CapturedLinkTarget.MaximumLength)) + { + /* This message is displayed on the debugger in Windows */ + DbgPrint("OB: Invalid symbolic link target - %wZ\n", + &CapturedLinkTarget); + return STATUS_INVALID_PARAMETER; + } + + /* Create the object */ Status = ObCreateObject(PreviousMode, ObSymbolicLinkType, ObjectAttributes, PreviousMode, NULL, - sizeof(SYMLINK_OBJECT), + sizeof(OBJECT_SYMBOLIC_LINK), 0, 0, (PVOID*)&SymbolicLink); if (NT_SUCCESS(Status)) { - SymbolicLink->TargetName.Length = 0; - SymbolicLink->TargetName.MaximumLength = CapturedLinkTarget.Length + + /* Success! Fill in the creation time immediately */ + KeQuerySystemTime(&SymbolicLink->CreationTime); + + /* Setup the target name */ + SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length; + SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.Length + sizeof(WCHAR); - SymbolicLink->TargetName.Buffer = - ExAllocatePoolWithTag(NonPagedPool, - SymbolicLink->TargetName.MaximumLength, + SymbolicLink->LinkTarget.Buffer = + ExAllocatePoolWithTag(PagedPool, + CapturedLinkTarget.MaximumLength, TAG_SYMLINK_TARGET); - - RtlCopyUnicodeString(&SymbolicLink->TargetName, &CapturedLinkTarget); - - DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer); - - ZwQuerySystemTime (&SymbolicLink->CreateTime); - - Status = ObInsertObject((PVOID)SymbolicLink, + if (!SymbolicLink->LinkTarget.Buffer) return STATUS_NO_MEMORY; + + /* Copy it */ + RtlMoveMemory(SymbolicLink->LinkTarget.Buffer, + CapturedLinkTarget.Buffer, + CapturedLinkTarget.MaximumLength); + + /* Initialize the remaining name, dos drive index and target object */ + SymbolicLink->LinkTargetObject = NULL; + SymbolicLink->DosDeviceDriveIndex = 0; + RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL); + + /* Insert it into the object tree */ + Status = ObInsertObject(SymbolicLink, NULL, DesiredAccess, 0, @@ -276,18 +326,22 @@ { _SEH_TRY { + /* Return the handle to caller */ *LinkHandle = hLink; } _SEH_HANDLE { + /* Get exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END; } + + /* ReactOS Hack: Our ObInsertObject references an object twice */ ObDereferenceObject(SymbolicLink); }
- ReleaseCapturedUnicodeString(&CapturedLinkTarget, PreviousMode); + /* Return status to caller */ return Status; }
@@ -322,27 +376,26 @@ NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE();
+ /* Check if we need to probe parameters */ if(PreviousMode != KernelMode) { _SEH_TRY { + /* Probe the return handle */ ProbeForWriteHandle(LinkHandle); } _SEH_HANDLE { + /* Exception, get the error code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
- if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n", - ObjectAttributes->ObjectName); - + /* Probing failed, return the error code */ + if(!NT_SUCCESS(Status)) return Status; + } + + /* Open the object */ Status = ObOpenObjectByName(ObjectAttributes, ObSymbolicLinkType, NULL, @@ -350,19 +403,22 @@ DesiredAccess, NULL, &hLink); - if(NT_SUCCESS(Status)) + if (NT_SUCCESS(Status)) { _SEH_TRY { + /* Return the handle to caller */ *LinkHandle = hLink; } _SEH_HANDLE { + /* Get exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END; }
+ /* Return status to caller */ return Status; }
@@ -393,46 +449,47 @@ OUT PULONG ResultLength OPTIONAL) { UNICODE_STRING SafeLinkTarget; - PSYMLINK_OBJECT SymlinkObject; + POBJECT_SYMBOLIC_LINK SymlinkObject; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status = STATUS_SUCCESS; - ULONG LengthRequired; + ULONG LengthUsed; PAGED_CODE();
if(PreviousMode != KernelMode) { _SEH_TRY { - /* probe the unicode string and buffers supplied */ - ProbeForWrite(LinkTarget, sizeof(UNICODE_STRING), sizeof(ULONG)); - + /* Probe the unicode string for read and write */ + ProbeForRead(LinkTarget, sizeof(UNICODE_STRING), sizeof(WCHAR)); + ProbeForWriteUshort(&LinkTarget->Length); + ProbeForWriteUshort(&LinkTarget->MaximumLength); + + /* Probe the unicode string's buffer for write */ SafeLinkTarget = *LinkTarget; - ProbeForWrite(SafeLinkTarget.Buffer, SafeLinkTarget.MaximumLength, - sizeof(WCHAR)); - - if(ResultLength != NULL) - { - ProbeForWriteUlong(ResultLength); - } + sizeof(CHAR)); + + /* Probe the return length */ + if(ResultLength) ProbeForWriteUlong(ResultLength); } _SEH_HANDLE { + /* Probe failure: get exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
- if(!NT_SUCCESS(Status)) - { - return Status; - } + /* Probe failed, return status */ + if(!NT_SUCCESS(Status)) return Status; } else { + /* No need to probe */ SafeLinkTarget = *LinkTarget; }
+ /* Reference the object */ Status = ObReferenceObjectByHandle(LinkHandle, SYMBOLIC_LINK_QUERY, ObSymbolicLinkType, @@ -441,44 +498,59 @@ NULL); if (NT_SUCCESS(Status)) { - LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR); - + /* Lock the object type */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&ObSymbolicLinkType->Mutex, TRUE); + + /* + * So here's the thing: If you specify a return length, then the + * implementation will use the maximum length. If you don't, then + * it will use the length. + */ + LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength : + SymlinkObject->LinkTarget.Length; + + /* Enter SEH so we can safely copy */ _SEH_TRY { - if(SafeLinkTarget.MaximumLength >= LengthRequired) + /* Make sure our buffer will fit */ + if (LengthUsed <= SafeLinkTarget.MaximumLength) { - /* - * Don't pass TargetLink to RtlCopyUnicodeString here because - * the caller might have modified the structure which could - * lead to a copy into kernel memory! - */ - RtlCopyUnicodeString(&SafeLinkTarget, - &SymlinkObject->TargetName); - SafeLinkTarget.Buffer[SafeLinkTarget.Length / - sizeof(WCHAR)] = UNICODE_NULL; - - /* Copy back the new UNICODE_STRING structure */ - *LinkTarget = SafeLinkTarget; + /* Copy the buffer */ + RtlMoveMemory(SafeLinkTarget.Buffer, + SymlinkObject->LinkTarget.Buffer, + LengthUsed); + + /* Copy the new length */ + LinkTarget->Length = SymlinkObject->LinkTarget.Length; } else { + /* Otherwise set the failure status */ Status = STATUS_BUFFER_TOO_SMALL; }
- if(ResultLength != NULL) + /* In both cases, check if the required length was requested */ + if (ResultLength) { - *ResultLength = LengthRequired; + /* Then return it */ + *ResultLength = SymlinkObject->LinkTarget.MaximumLength; } } _SEH_HANDLE { + /* Get the error code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
+ /* Unlock the object type and reference the object */ + ExReleaseResourceLite(&ObSymbolicLinkType->Mutex); + KeLeaveCriticalRegion(); ObDereferenceObject(SymlinkObject); }
+ /* Return query status */ return Status; }