update for HEAD-2003050101
[reactos.git] / ntoskrnl / ob / symlink.c
diff --git a/ntoskrnl/ob/symlink.c b/ntoskrnl/ob/symlink.c
new file mode 100644 (file)
index 0000000..83cf74f
--- /dev/null
@@ -0,0 +1,339 @@
+/* $Id$
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/ob/symlink.c
+ * PURPOSE:         Implements symbolic links
+ * PROGRAMMER:      David Welch (welch@mcmail.com)
+ * UPDATE HISTORY:
+ *                  Created 22/05/98
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <limits.h>
+#include <ddk/ntddk.h>
+#include <internal/ob.h>
+
+#define NDEBUG
+#include <internal/debug.h>
+
+/* GLOBALS ******************************************************************/
+
+typedef struct
+{
+       CSHORT                  Type;
+       CSHORT                  Size;
+       UNICODE_STRING          TargetName;
+       OBJECT_ATTRIBUTES       Target;
+} SYMLNK_OBJECT, *PSYMLNK_OBJECT;
+
+POBJECT_TYPE ObSymbolicLinkType = NULL;
+
+static GENERIC_MAPPING ObpSymbolicLinkMapping = {
+       STANDARD_RIGHTS_READ|SYMBOLIC_LINK_QUERY,
+       STANDARD_RIGHTS_WRITE,
+       STANDARD_RIGHTS_EXECUTE|SYMBOLIC_LINK_QUERY,
+       SYMBOLIC_LINK_ALL_ACCESS};
+
+#define TAG_SYMLINK_TTARGET     TAG('S', 'Y', 'T', 'T')
+#define TAG_SYMLINK_TARGET      TAG('S', 'Y', 'M', 'T')
+
+/* FUNCTIONS ****************************************************************/
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ObpCreateSymbolicLink
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURNN VALUE
+ *     Status.
+ *
+ * REVISIONS
+ */
+NTSTATUS STDCALL
+ObpCreateSymbolicLink(PVOID Object,
+                     PVOID Parent,
+                     PWSTR RemainingPath,
+                     POBJECT_ATTRIBUTES ObjectAttributes)
+{
+  return(STATUS_SUCCESS);
+}
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ObpDeleteSymbolicLink
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURNN VALUE
+ *     Status.
+ *
+ * REVISIONS
+ */
+VOID STDCALL
+ObpDeleteSymbolicLink(PVOID ObjectBody)
+{
+  PSYMLNK_OBJECT SymlinkObject = (PSYMLNK_OBJECT)ObjectBody;
+
+  RtlFreeUnicodeString(&SymlinkObject->TargetName);
+}
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ObpParseSymbolicLink
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ */
+NTSTATUS STDCALL
+ObpParseSymbolicLink(PVOID Object,
+                    PVOID * NextObject,
+                    PUNICODE_STRING FullPath,
+                    PWSTR * RemainingPath,
+                    ULONG Attributes)
+{
+  PSYMLNK_OBJECT SymlinkObject = (PSYMLNK_OBJECT) Object;
+  UNICODE_STRING TargetPath;
+
+  DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
+
+  /*
+   * Stop parsing if the entire path has been parsed and
+   * the desired object is a symbolic link object.
+   */
+  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,
+                                            TAG_SYMLINK_TTARGET);
+   wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer);
+   if (RemainingPath && *RemainingPath)
+     {
+       wcscat(TargetPath.Buffer, *RemainingPath);
+     }
+
+   /* transfer target path buffer into FullPath */
+   RtlFreeUnicodeString(FullPath);
+   FullPath->Length = TargetPath.Length;
+   FullPath->MaximumLength = TargetPath.MaximumLength;
+   FullPath->Buffer = TargetPath.Buffer;
+
+   /* reinitialize RemainingPath for reparsing */
+   *RemainingPath = FullPath->Buffer;
+
+   *NextObject = NULL;
+   return STATUS_REPARSE;
+}
+
+
+/**********************************************************************
+ * NAME                                                        INTERNAL
+ *     ObInitSymbolicLinkImplementation
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *     None.
+ *
+ * RETURNN VALUE
+ *     None.
+ *
+ * REVISIONS
+ */
+VOID ObInitSymbolicLinkImplementation (VOID)
+{
+  ObSymbolicLinkType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
+
+  ObSymbolicLinkType->Tag = TAG('S', 'Y', 'M', 'T');
+  ObSymbolicLinkType->TotalObjects = 0;
+  ObSymbolicLinkType->TotalHandles = 0;
+  ObSymbolicLinkType->MaxObjects = ULONG_MAX;
+  ObSymbolicLinkType->MaxHandles = ULONG_MAX;
+  ObSymbolicLinkType->PagedPoolCharge = 0;
+  ObSymbolicLinkType->NonpagedPoolCharge = sizeof(SYMLNK_OBJECT);
+  ObSymbolicLinkType->Mapping = &ObpSymbolicLinkMapping;
+  ObSymbolicLinkType->Dump = NULL;
+  ObSymbolicLinkType->Open = NULL;
+  ObSymbolicLinkType->Close = NULL;
+  ObSymbolicLinkType->Delete = ObpDeleteSymbolicLink;
+  ObSymbolicLinkType->Parse = ObpParseSymbolicLink;
+  ObSymbolicLinkType->Security = NULL;
+  ObSymbolicLinkType->QueryName = NULL;
+  ObSymbolicLinkType->OkayToClose = NULL;
+  ObSymbolicLinkType->Create = ObpCreateSymbolicLink;
+  ObSymbolicLinkType->DuplicationNotify = NULL;
+
+  RtlInitUnicodeStringFromLiteral(&ObSymbolicLinkType->TypeName,
+                                 L"SymbolicLink");
+
+  ObpCreateTypeObject(ObSymbolicLinkType);
+}
+
+
+/**********************************************************************
+ * NAME                                                EXPORTED
+ *     NtCreateSymbolicLinkObject
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ */
+NTSTATUS STDCALL
+NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,
+                          IN ACCESS_MASK DesiredAccess,
+                          IN POBJECT_ATTRIBUTES ObjectAttributes,
+                          IN PUNICODE_STRING DeviceName)
+{
+  PSYMLNK_OBJECT SymbolicLink;
+  NTSTATUS Status;
+
+  assert_irql(PASSIVE_LEVEL);
+
+  DPRINT("NtCreateSymbolicLinkObject(SymbolicLinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, DeviceName %wZ)\n",
+        SymbolicLinkHandle,
+        DesiredAccess,
+        ObjectAttributes,
+        DeviceName);
+
+  Status = ObCreateObject(SymbolicLinkHandle,
+                         DesiredAccess,
+                         ObjectAttributes,
+                         ObSymbolicLinkType,
+                         (PVOID*)&SymbolicLink);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  SymbolicLink->TargetName.Length = 0;
+  SymbolicLink->TargetName.MaximumLength = 
+    ((wcslen(DeviceName->Buffer) + 1) * sizeof(WCHAR));
+  SymbolicLink->TargetName.Buffer = 
+    ExAllocatePoolWithTag(NonPagedPool,
+                         SymbolicLink->TargetName.MaximumLength,
+                         TAG_SYMLINK_TARGET);
+  RtlCopyUnicodeString(&SymbolicLink->TargetName,
+                      DeviceName);
+
+  DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
+
+  InitializeObjectAttributes(&SymbolicLink->Target,
+                            &SymbolicLink->TargetName,
+                            0,
+                            NULL,
+                            NULL);
+
+  DPRINT("%s() = STATUS_SUCCESS\n",__FUNCTION__);
+  ObDereferenceObject(SymbolicLink);
+
+  return(STATUS_SUCCESS);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     NtOpenSymbolicLinkObject
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ */
+NTSTATUS STDCALL
+NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
+                        IN ACCESS_MASK DesiredAccess,
+                        IN POBJECT_ATTRIBUTES ObjectAttributes)
+{
+  DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
+        ObjectAttributes->ObjectName);
+
+  return(ObOpenObjectByName(ObjectAttributes,
+                           ObSymbolicLinkType,
+                           NULL,
+                           KeGetPreviousMode(),
+                           DesiredAccess,
+                           NULL,
+                           LinkHandle));
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     NtQuerySymbolicLinkObject
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ */
+NTSTATUS STDCALL
+NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
+                         IN OUT PUNICODE_STRING LinkTarget,
+                         OUT PULONG ReturnedLength OPTIONAL)
+{
+  PSYMLNK_OBJECT SymlinkObject;
+  NTSTATUS Status;
+
+  Status = ObReferenceObjectByHandle(LinkHandle,
+                                    SYMBOLIC_LINK_QUERY,
+                                    ObSymbolicLinkType,
+                                    KeGetPreviousMode(),
+                                    (PVOID *)&SymlinkObject,
+                                    NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  RtlCopyUnicodeString(LinkTarget,
+                      SymlinkObject->Target.ObjectName);
+  if (ReturnedLength != NULL)
+    {
+      *ReturnedLength = SymlinkObject->Target.Length;
+    }
+  ObDereferenceObject(SymlinkObject);
+
+  return(STATUS_SUCCESS);
+}
+
+/* EOF */