https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e12abf63c53670009f6843fa705ab7d392b66cf9

commit e12abf63c53670009f6843fa705ab7d392b66cf9
Author:     Pierre Schweitzer <pie...@reactos.org>
AuthorDate: Mon Aug 19 10:44:56 2019 +0200
Commit:     Pierre Schweitzer <pie...@reactos.org>
CommitDate: Mon Aug 19 10:45:50 2019 +0200

    [NTOSKRNL] Handle symlink parsing when it's bound to a specific object
---
 ntoskrnl/ob/oblink.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/ntoskrnl/ob/oblink.c b/ntoskrnl/ob/oblink.c
index 712143e1ed7..67cb36385dd 100644
--- a/ntoskrnl/ob/oblink.c
+++ b/ntoskrnl/ob/oblink.c
@@ -5,6 +5,7 @@
 * PURPOSE:         Implements symbolic links
 * PROGRAMMERS:     Alex Ionescu (a...@relsoft.net)
 *                  David Welch (we...@mcmail.com)
+*                  Pierre Schweitzer
 */
 
 /* INCLUDES *****************************************************************/
@@ -481,7 +482,98 @@ ObpParseSymbolicLink(IN PVOID ParsedObject,
     /* Check if this symlink is bound to a specific object */
     if (SymlinkObject->LinkTargetObject)
     {
-        UNIMPLEMENTED;
+        /* No name to reparse, directly reparse the object */
+        if (!SymlinkObject->LinkTargetRemaining.Length)
+        {
+            *NextObject = SymlinkObject->LinkTargetObject;
+            return STATUS_REPARSE_OBJECT;
+        }
+
+        TempLength = SymlinkObject->LinkTargetRemaining.Length;
+        /* The target and remaining names aren't empty, so check for slashes */
+        if (SymlinkObject->LinkTargetRemaining.Buffer[TempLength / 
sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR &&
+            RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
+        {
+            /* Reduce the length by one to cut off the extra '\' */
+            TempLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+        }
+
+        /* Calculate the new length */
+        LengthUsed = TempLength + RemainingName->Length;
+        LengthUsed += (sizeof(WCHAR) * (RemainingName->Buffer - 
FullPath->Buffer));
+
+        /* Check if it's not too much */
+        if (LengthUsed > 0xFFF0)
+            return STATUS_NAME_TOO_LONG;
+
+        /* If FullPath is enough, use it */
+        if (FullPath->MaximumLength > LengthUsed)
+        {
+            /* Update remaining length if appropriate */
+            if (RemainingName->Length)
+            {
+                RtlMoveMemory((PVOID)((ULONG_PTR)RemainingName->Buffer + 
TempLength),
+                              RemainingName->Buffer,
+                              RemainingName->Length);
+            }
+
+            /* And move the target object name */
+            RtlCopyMemory(RemainingName->Buffer,
+                          SymlinkObject->LinkTargetRemaining.Buffer,
+                          TempLength);
+
+            /* Finally update the full path with what we parsed */
+            FullPath->Length += SymlinkObject->LinkTargetRemaining.Length;
+            RemainingName->Length += SymlinkObject->LinkTargetRemaining.Length;
+            RemainingName->MaximumLength += RemainingName->Length + 
sizeof(WCHAR);
+            FullPath->Buffer[FullPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+            /* And reparse */
+            *NextObject = SymlinkObject->LinkTargetObject;
+            return STATUS_REPARSE_OBJECT;
+        }
+
+        /* FullPath is not enough, we'll have to reallocate */
+        MaximumLength = LengthUsed + sizeof(WCHAR);
+        NewTargetPath = ExAllocatePoolWithTag(NonPagedPool,
+                                              MaximumLength,
+                                              OB_NAME_TAG);
+        if (!NewTargetPath) return STATUS_INSUFFICIENT_RESOURCES;
+
+        /* Copy path begin */
+        RtlCopyMemory(NewTargetPath,
+                      FullPath->Buffer,
+                      sizeof(WCHAR) * (RemainingName->Buffer - 
FullPath->Buffer));
+
+        /* Copy path end (if any) */
+        if (RemainingName->Length)
+        {
+            
RtlCopyMemory((PVOID)((ULONG_PTR)&NewTargetPath[RemainingName->Buffer - 
FullPath->Buffer] + TempLength),
+                          RemainingName->Buffer,
+                          RemainingName->Length);
+        }
+
+        /* And finish path with bound object */
+        RtlCopyMemory(&NewTargetPath[RemainingName->Buffer - FullPath->Buffer],
+                      SymlinkObject->LinkTargetRemaining.Buffer,
+                      TempLength);
+
+        /* Free old buffer */
+        ExFreePool(FullPath->Buffer);
+
+        /* Set new buffer in FullPath */
+        FullPath->Buffer = NewTargetPath;
+        FullPath->MaximumLength = MaximumLength;
+        FullPath->Length = LengthUsed;
+
+        /* Update remaining with what we handled */
+        RemainingName->Length = LengthUsed + (ULONG_PTR)NewTargetPath - 
(ULONG_PTR)&NewTargetPath[RemainingName->Buffer - FullPath->Buffer];
+        RemainingName->Buffer = &NewTargetPath[RemainingName->Buffer - 
FullPath->Buffer];
+        RemainingName->MaximumLength = RemainingName->Length + sizeof(WCHAR);
+
+        /* Reparse! */
+        *NextObject = SymlinkObject->LinkTargetObject;
+        return STATUS_REPARSE_OBJECT;
     }
 
     /* Set the target path and length */

Reply via email to