- Implemented ObQueryNameString().
authorEric Kohl <eric.kohl@reactos.org>
Mon, 2 Jun 2003 10:04:28 +0000 (10:04 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Mon, 2 Jun 2003 10:04:28 +0000 (10:04 +0000)
- Added 'QueryName' object function.
- Implemented 'QueryName' function for file objects.

svn path=/trunk/; revision=4822

reactos/include/ntos/obtypes.h
reactos/include/ntos/zwtypes.h
reactos/ntoskrnl/io/iomgr.c
reactos/ntoskrnl/ntoskrnl.def
reactos/ntoskrnl/ntoskrnl.edf
reactos/ntoskrnl/ob/dirobj.c
reactos/ntoskrnl/ob/ntobj.c
reactos/ntoskrnl/ob/object.c

index a656140..cf4fd5a 100755 (executable)
@@ -1,6 +1,6 @@
 #ifndef _INCLUDE_DDK_OBTYPES_H
 #define _INCLUDE_DDK_OBTYPES_H
-/* $Id: obtypes.h,v 1.2 2003/06/01 14:59:01 chorns Exp $ */
+/* $Id: obtypes.h,v 1.3 2003/06/02 10:02:16 ekohl Exp $ */
 struct _DIRECTORY_OBJECT;
 struct _OBJECT_ATTRIBUTES;
 
@@ -8,9 +8,15 @@ struct _OBJECT_ATTRIBUTES;
 
 typedef ULONG ACCESS_STATE, *PACCESS_STATE;
 
-typedef struct _OBJECT_HANDLE_INFORMATION {
-    ULONG HandleAttributes;
-    ACCESS_MASK GrantedAccess;
+typedef struct _OBJECT_NAME_INFORMATION
+{
+  UNICODE_STRING Name;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef struct _OBJECT_HANDLE_INFORMATION
+{
+  ULONG HandleAttributes;
+  ACCESS_MASK GrantedAccess;
 } OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION;
 
 #endif /* __USE_W32API */
@@ -110,16 +116,22 @@ typedef struct _OBJECT_TYPE
                                    SECURITY_INFORMATION SecurityInformation,
                                    PSECURITY_DESCRIPTOR SecurityDescriptor,
                                    PULONG BufferLength);
-  
+
   /*
+   * PURPOSE: Called to query the name of the object
+   * RETURNS
+   *     STATUS_SUCCESS       NextObject was found
    */
-  VOID STDCALL_FUNC (*QueryName)(VOID);
-   
+  NTSTATUS STDCALL_FUNC (*QueryName)(PVOID ObjectBody,
+                                    POBJECT_NAME_INFORMATION ObjectNameInfo,
+                                    ULONG Length,
+                                    PULONG ReturnLength);
+
   /*
    * PURPOSE: Called when a process asks to close the object
    */
   VOID STDCALL_FUNC (*OkayToClose)(VOID);
-  
+
   NTSTATUS STDCALL_FUNC (*Create)(PVOID ObjectBody,
                             PVOID Parent,
                             PWSTR RemainingPath,
index 50ef697..15b0a1b 100755 (executable)
@@ -720,12 +720,6 @@ typedef struct _THREAD_BASIC_INFORMATION
   KPRIORITY BasePriority;
 } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
 
-// object information
-
-typedef struct _OBJECT_NAME_INFORMATION
-{
-       UNICODE_STRING  Name;
-} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
 
 // file information
 
index c0e7fff..64e727b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: iomgr.c,v 1.33 2003/05/22 00:47:04 gdalsnes Exp $
+/* $Id: iomgr.c,v 1.34 2003/06/02 10:02:56 ekohl Exp $
  *
  * COPYRIGHT:            See COPYING in the top level directory
  * PROJECT:              ReactOS kernel
@@ -86,6 +86,7 @@ IopCloseFile(PVOID ObjectBody,
    }
 }
 
+
 VOID STDCALL
 IopDeleteFile(PVOID ObjectBody)
 {
@@ -132,6 +133,71 @@ IopDeleteFile(PVOID ObjectBody)
 }
 
 
+NTSTATUS STDCALL
+IopQueryNameFile(PVOID ObjectBody,
+                POBJECT_NAME_INFORMATION ObjectNameInfo,
+                ULONG Length,
+                PULONG ReturnLength)
+{
+  POBJECT_NAME_INFORMATION LocalInfo;
+  PFILE_NAME_INFORMATION FileNameInfo;
+  PFILE_OBJECT FileObject;
+  ULONG LocalReturnLength;
+  NTSTATUS Status;
+
+  DPRINT ("IopQueryNameFile() called\n");
+
+  FileObject = (PFILE_OBJECT)ObjectBody;
+
+  LocalInfo = ExAllocatePool (NonPagedPool,
+                             sizeof(OBJECT_NAME_INFORMATION) +
+                               MAX_PATH * sizeof(WCHAR));
+  if (LocalInfo == NULL)
+    return STATUS_INSUFFICIENT_RESOURCES;
+
+  Status = ObQueryNameString (FileObject->DeviceObject->Vpb->RealDevice,
+                             LocalInfo,
+                             MAX_PATH * sizeof(WCHAR),
+                             &LocalReturnLength);
+  if (!NT_SUCCESS (Status))
+    {
+      ExFreePool (LocalInfo);
+      return Status;
+    }
+  DPRINT ("Device path: %wZ\n", &LocalInfo->Name);
+
+  Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
+                                          &LocalInfo->Name);
+
+  ExFreePool (LocalInfo);
+
+  FileNameInfo = ExAllocatePool (NonPagedPool,
+                                MAX_PATH * sizeof(WCHAR) + sizeof(ULONG));
+  if (FileNameInfo == NULL)
+    return STATUS_INSUFFICIENT_RESOURCES;
+
+  Status = IoQueryFileInformation (FileObject,
+                                  FileNameInformation,
+                                  MAX_PATH * sizeof(WCHAR) + sizeof(ULONG),
+                                  FileNameInfo,
+                                  NULL);
+  if (Status != STATUS_SUCCESS)
+    {
+      ExFreePool (FileNameInfo);
+      return Status;
+    }
+
+  Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
+                                    FileNameInfo->FileName);
+
+  DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name);
+
+  ExFreePool (FileNameInfo);
+
+  return Status;
+}
+
+
 VOID IoInit (VOID)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
@@ -144,7 +210,7 @@ VOID IoInit (VOID)
   /*
    * Register iomgr types: DeviceObjectType
    */
-  IoDeviceObjectType = ExAllocatePool (NonPagedPool, 
+  IoDeviceObjectType = ExAllocatePool (NonPagedPool,
                                       sizeof (OBJECT_TYPE));
   
   IoDeviceObjectType->Tag = TAG_DEVICE_TYPE;
@@ -188,7 +254,7 @@ VOID IoInit (VOID)
   IoFileObjectType->Delete = IopDeleteFile;
   IoFileObjectType->Parse = NULL;
   IoFileObjectType->Security = NULL;
-  IoFileObjectType->QueryName = NULL;
+  IoFileObjectType->QueryName = IopQueryNameFile;
   IoFileObjectType->OkayToClose = NULL;
   IoFileObjectType->Create = IopCreateFile;
   IoFileObjectType->DuplicationNotify = NULL;
index 8802b3a..6531b5a 100644 (file)
@@ -1,4 +1,4 @@
-; $Id: ntoskrnl.def,v 1.152 2003/05/15 11:07:51 ekohl Exp $
+; $Id: ntoskrnl.def,v 1.153 2003/06/02 10:04:28 ekohl Exp $
 ;
 ; reactos/ntoskrnl/ntoskrnl.def
 ;
@@ -604,7 +604,7 @@ ObGetObjectSecurity@12
 ObMakeTemporaryObject@4
 ObOpenObjectByName@28
 ObOpenObjectByPointer@28
-;ObQueryNameString@16
+ObQueryNameString@16
 ;ObQueryObjectAuditingByHandle@8
 @ObfDereferenceObject@4
 @ObfReferenceObject@4
index ea990d5..a62073b 100644 (file)
@@ -1,4 +1,4 @@
-; $Id: ntoskrnl.edf,v 1.138 2003/05/15 11:07:51 ekohl Exp $
+; $Id: ntoskrnl.edf,v 1.139 2003/06/02 10:04:28 ekohl Exp $
 ;
 ; reactos/ntoskrnl/ntoskrnl.def
 ;
@@ -603,7 +603,7 @@ ObGetObjectSecurity=ObGetObjectSecurity@12
 ObMakeTemporaryObject=ObMakeTemporaryObject@4
 ObOpenObjectByName=ObOpenObjectByName@28
 ObOpenObjectByPointer=ObOpenObjectByPointer@28
-;ObQueryNameString=ObQueryNameString@16
+ObQueryNameString=ObQueryNameString@16
 ;ObQueryObjectAuditingByHandle=ObQueryObjectAuditingByHandle@8
 ObfDereferenceObject=@ObfDereferenceObject@4
 ObfReferenceObject=@ObfReferenceObject@4
index 92e7d10..f70cd8b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dirobj.c,v 1.16 2002/09/08 10:23:38 chorns Exp $
+/* $Id: dirobj.c,v 1.17 2003/06/02 10:03:52 ekohl Exp $
  *
  * COPYRIGHT:      See COPYING in the top level directory
  * PROJECT:        ReactOS kernel
  * NOTES
  *     Undocumented.
  */
-NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
-                                      ACCESS_MASK DesiredAccess,
-                                      POBJECT_ATTRIBUTES ObjectAttributes)
+NTSTATUS STDCALL
+NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle,
+                      IN ACCESS_MASK DesiredAccess,
+                      IN POBJECT_ATTRIBUTES ObjectAttributes)
 {
    PVOID Object;
    NTSTATUS Status;
@@ -121,14 +122,14 @@ NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
  *             G.Nebbett "WNT/W2k Native API Reference".
  *             Mostly rewritten.
  */
-NTSTATUS STDCALL NtQueryDirectoryObject (IN HANDLE DirObjHandle,
-                                        OUT POBJDIR_INFORMATION 
-                                                   DirObjInformation, 
-                                        IN ULONG BufferLength, 
-                                        IN BOOLEAN ReturnSingleEntry,
-                                        IN BOOLEAN RestartScan, 
-                                        IN OUT PULONG ObjectIndex,
-                                        OUT PULONG DataWritten OPTIONAL)
+NTSTATUS STDCALL
+NtQueryDirectoryObject (IN HANDLE DirObjHandle,
+                       OUT POBJDIR_INFORMATION DirObjInformation,
+                       IN ULONG BufferLength,
+                       IN BOOLEAN ReturnSingleEntry,
+                       IN BOOLEAN RestartScan,
+                       IN OUT PULONG ObjectIndex,
+                       OUT PULONG DataWritten OPTIONAL)
 {
     PDIRECTORY_OBJECT   dir = NULL;
     PLIST_ENTRY         current_entry = NULL;
@@ -326,9 +327,9 @@ NTSTATUS STDCALL NtQueryDirectoryObject (IN HANDLE DirObjHandle,
  *     Status.
  */
 NTSTATUS STDCALL
-NtCreateDirectoryObject(PHANDLE DirectoryHandle,
-                       ACCESS_MASK DesiredAccess,
-                       POBJECT_ATTRIBUTES ObjectAttributes)
+NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle,
+                        IN ACCESS_MASK DesiredAccess,
+                        IN POBJECT_ATTRIBUTES ObjectAttributes)
 {
    PDIRECTORY_OBJECT dir;
 
index 18d9ba3..e4d9016 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ntobj.c,v 1.12 2003/06/01 15:09:34 ekohl Exp $
+/* $Id: ntobj.c,v 1.13 2003/06/02 10:03:52 ekohl Exp $
  *
  * COPYRIGHT:     See COPYING in the top level directory
  * PROJECT:       ReactOS kernel
@@ -43,41 +43,6 @@ NtSetInformationObject (IN HANDLE ObjectHandle,
 }
 
 
-NTSTATUS
-internalNameBuilder(POBJECT_HEADER ObjectHeader,
-                   PUNICODE_STRING String)
-/* So, what's the purpose of this function?
-   It will take any OBJECT_HEADER and traverse the Parent structure up to the root
-   and form the name, i.e. this will only work on objects where the Parent/Name fields
-   have any meaning (not files) */
-{
-  NTSTATUS Status;
-
-  if (ObjectHeader->Parent)
-    {
-      Status = internalNameBuilder(BODY_TO_HEADER(ObjectHeader->Parent),
-                                  String);
-      if (Status != STATUS_SUCCESS)
-       {
-         return Status;
-       }
-    }
-
-  if (ObjectHeader->Name.Buffer)
-    {
-      Status = RtlAppendUnicodeToString(String,
-                                       L"\\");
-      if (Status != STATUS_SUCCESS)
-       return Status;
-
-      return RtlAppendUnicodeStringToString(String,
-                                           &ObjectHeader->Name);
-    }
-
-  return STATUS_SUCCESS;
-}
-
-
 /*Very, very, very new implementation. Test it!
 
   Probably we should add meaning to QueryName in POBJECT_TYPE, no matter if we know
@@ -107,13 +72,10 @@ NtQueryObject (IN HANDLE ObjectHandle,
               IN ULONG Length,
               OUT PULONG ReturnLength)
 {
-  POBJECT_NAME_INFORMATION NameInfo;
   POBJECT_TYPE_INFORMATION typeinfo;
-  PFILE_NAME_INFORMATION filenameinfo;
+  POBJECT_HEADER ObjectHeader;
   PVOID Object;
   NTSTATUS Status;
-  POBJECT_HEADER ObjectHeader;
-  PFILE_OBJECT fileob;
 
   Status = ObReferenceObjectByHandle (ObjectHandle,
                                      0,
@@ -131,88 +93,11 @@ NtQueryObject (IN HANDLE ObjectHandle,
   switch (ObjectInformationClass)
     {
       case ObjectNameInformation:
-#if 0
        Status = ObQueryNameString (Object,
                                    (POBJECT_NAME_INFORMATION)ObjectInformation,
                                    Length,
                                    ReturnLength);
        break;
-#endif
-
-       if (Length < sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR))
-         return STATUS_INVALID_BUFFER_SIZE;
-
-       NameInfo = (POBJECT_NAME_INFORMATION)ObjectInformation;
-       *ReturnLength = 0;
-
-       NameInfo->Name.MaximumLength = sizeof(WCHAR);
-       NameInfo->Name.Length = 0;
-       NameInfo->Name.Buffer = (PWCHAR)((ULONG_PTR)NameInfo + sizeof(OBJECT_NAME_INFORMATION));
-       NameInfo->Name.Buffer[0] = 0;
-
-       // FIXME: Temporary QueryName implementation, or at least separate functions
-       if (ObjectHeader->Type==InternalFileType)
-         {
-           NameInfo->Name.MaximumLength = Length - sizeof(OBJECT_NAME_INFORMATION);
-           fileob = (PFILE_OBJECT) Object;
-           Status = internalNameBuilder(BODY_TO_HEADER(fileob->DeviceObject->Vpb->RealDevice),
-                                        &NameInfo->Name);
-           if (Status != STATUS_SUCCESS)
-             {
-               NameInfo->Name.MaximumLength = 0;
-               break;
-             }
-
-           filenameinfo = ExAllocatePool (NonPagedPool,
-                                          MAX_PATH * sizeof(WCHAR) + sizeof(ULONG));
-           if (filenameinfo == NULL)
-             {
-               NameInfo->Name.MaximumLength = 0;
-               Status = STATUS_INSUFFICIENT_RESOURCES;
-               break;
-             }
-
-           Status = IoQueryFileInformation (fileob,
-                                            FileNameInformation,
-                                            MAX_PATH * sizeof(WCHAR) + sizeof(ULONG),
-                                            filenameinfo,
-                                            NULL);
-           if (Status != STATUS_SUCCESS)
-             {
-               NameInfo->Name.MaximumLength = 0;
-               ExFreePool (filenameinfo);
-               break;
-             }
-
-           Status = RtlAppendUnicodeToString (&(NameInfo->Name),
-                                              filenameinfo->FileName);
-
-           ExFreePool (filenameinfo);
-
-           if (NT_SUCCESS(Status))
-             {
-               NameInfo->Name.MaximumLength = NameInfo->Name.Length + sizeof(WCHAR);
-               *ReturnLength = sizeof(OBJECT_NAME_INFORMATION) + NameInfo->Name.MaximumLength;
-             }
-         }
-       else if (ObjectHeader->Name.Buffer)
-         {
-           // If it's got a name there, we can probably just make the full path through Name and Parent
-           NameInfo->Name.MaximumLength = Length - sizeof(OBJECT_NAME_INFORMATION);
-
-           Status = internalNameBuilder (ObjectHeader,
-                                         &NameInfo->Name);
-           if (NT_SUCCESS(Status))
-             {
-               NameInfo->Name.MaximumLength = NameInfo->Name.Length + sizeof(WCHAR);
-               *ReturnLength = sizeof(OBJECT_NAME_INFORMATION) + NameInfo->Name.MaximumLength;
-             }
-         }
-       else
-         {
-           Status = STATUS_NOT_IMPLEMENTED;
-         }
-       break;
 
       case ObjectTypeInformation:
        typeinfo = (POBJECT_TYPE_INFORMATION)ObjectInformation;
index 9c43d77..fc3e3dd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: object.c,v 1.59 2003/05/11 19:41:22 ekohl Exp $
+/* $Id: object.c,v 1.60 2003/06/02 10:03:52 ekohl Exp $
  * 
  * COPYRIGHT:     See COPYING in the top level directory
  * PROJECT:       ReactOS kernel
@@ -21,6 +21,7 @@
 #define NDEBUG
 #include <internal/debug.h>
 
+
 /* FUNCTIONS ************************************************************/
 
 PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
@@ -28,6 +29,7 @@ PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
    return(((void *)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
 }
 
+
 POBJECT_HEADER BODY_TO_HEADER(PVOID body)
 {
    PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
@@ -219,6 +221,122 @@ NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
 }
 
 
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     ObQueryNameString@16
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ */
+NTSTATUS STDCALL
+ObQueryNameString (IN PVOID Object,
+                  OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+                  IN ULONG Length,
+                  OUT PULONG ReturnLength)
+{
+  POBJECT_NAME_INFORMATION LocalInfo;
+  POBJECT_HEADER ObjectHeader;
+  ULONG LocalReturnLength;
+  NTSTATUS Status;
+
+  *ReturnLength = 0;
+
+  if (Length < sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR))
+    return STATUS_INVALID_BUFFER_SIZE;
+
+  ObjectNameInfo->Name.MaximumLength = Length - sizeof(OBJECT_NAME_INFORMATION);
+  ObjectNameInfo->Name.Length = 0;
+  ObjectNameInfo->Name.Buffer =
+    (PWCHAR)((ULONG_PTR)ObjectNameInfo + sizeof(OBJECT_NAME_INFORMATION));
+  ObjectNameInfo->Name.Buffer[0] = 0;
+
+  ObjectHeader = BODY_TO_HEADER(Object);
+
+  if (ObjectHeader->ObjectType != NULL &&
+      ObjectHeader->ObjectType->QueryName != NULL)
+    {
+      DPRINT ("Calling %x\n", ObjectHeader->ObjectType->QueryName);
+      Status = ObjectHeader->ObjectType->QueryName (Object,
+                                                   ObjectNameInfo,
+                                                   Length,
+                                                   ReturnLength);
+      if (!NT_SUCCESS (Status))
+       return Status;
+
+      Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
+                                              &ObjectHeader->Name);
+    }
+  else if (ObjectHeader->Name.Length > 0 && ObjectHeader->Name.Buffer != NULL)
+    {
+      DPRINT ("Object does not have a 'QueryName' function\n");
+
+      if (ObjectHeader->Parent == NameSpaceRoot)
+       {
+         DPRINT ("Reached the root directory\n");
+         ObjectNameInfo->Name.Buffer[0] = 0;
+         Status = STATUS_SUCCESS;
+       }
+      else if (ObjectHeader->Parent != NULL)
+       {
+         LocalInfo = ExAllocatePool (NonPagedPool,
+                                     sizeof(OBJECT_NAME_INFORMATION) +
+                                     MAX_PATH * sizeof(WCHAR));
+         if (LocalInfo == NULL)
+           return STATUS_INSUFFICIENT_RESOURCES;
+
+         Status = ObQueryNameString (ObjectHeader->Parent,
+                                     LocalInfo,
+                                     MAX_PATH * sizeof(WCHAR),
+                                     &LocalReturnLength);
+         if (!NT_SUCCESS (Status))
+           {
+             ExFreePool (LocalInfo);
+             return Status;
+           }
+
+         Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
+                                                  &LocalInfo->Name);
+
+         ExFreePool (LocalInfo);
+
+         if (!NT_SUCCESS (Status))
+           return Status;
+       }
+
+      DPRINT ("Object path %wZ\n", &ObjectHeader->Name);
+      Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
+                                        L"\\");
+      if (!NT_SUCCESS (Status))
+       return Status;
+
+      Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
+                                              &ObjectHeader->Name);
+    }
+  else
+    {
+      DPRINT1 ("Object is unnamed\n");
+
+      /* FIXME */
+
+      Status = STATUS_UNSUCCESSFUL;
+    }
+
+  if (NT_SUCCESS (Status))
+    {
+      ObjectNameInfo->Name.MaximumLength =
+       ObjectNameInfo->Name.Length + sizeof(WCHAR);
+      *ReturnLength =
+       sizeof(OBJECT_NAME_INFORMATION) + ObjectNameInfo->Name.MaximumLength;
+      DPRINT ("Returned object path: %wZ\n", &ObjectNameInfo->Name);
+    }
+
+  return Status;
+}
+
+
 /**********************************************************************
  * NAME                                                        EXPORTED
  *     ObCreateObject@36
@@ -230,11 +348,11 @@ NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
  * RETURN VALUE
  */
 NTSTATUS STDCALL
-ObCreateObject(OUT PHANDLE Handle,
-              IN ACCESS_MASK DesiredAccess,
-              IN POBJECT_ATTRIBUTES ObjectAttributes,
-              IN POBJECT_TYPE Type,
-              OUT PVOID *Object)
+ObCreateObject (OUT PHANDLE Handle,
+               IN ACCESS_MASK DesiredAccess,
+               IN POBJECT_ATTRIBUTES ObjectAttributes,
+               IN POBJECT_TYPE Type,
+               OUT PVOID *Object)
 {
   PVOID Parent = NULL;
   UNICODE_STRING RemainingPath;