NtQueryDirectoryObject rewritten.
authorEmanuele Aliberti <ea@iol.it>
Tue, 1 May 2001 21:43:45 +0000 (21:43 +0000)
committerEmanuele Aliberti <ea@iol.it>
Tue, 1 May 2001 21:43:45 +0000 (21:43 +0000)
apps/objdir.c fixed to work under nt4sp6a AND reactos.

svn path=/trunk/; revision=1847

reactos/apps/utils/objdir/objdir.c
reactos/ntoskrnl/ob/dirobj.c

index 991a422..0304489 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: objdir.c,v 1.5 2000/08/11 17:18:31 ea Exp $
+/* $Id: objdir.c,v 1.6 2001/05/01 21:43:45 ea Exp $
  *
  * DESCRIPTION: Object Manager Simple Explorer
  * PROGRAMMER:  David Welch
@@ -9,6 +9,10 @@
  *     2000-08-11 (ea)
  *             Added symbolic link expansion.
  *             (tested under nt4sp4/x86)
+ *     2001-05-01 (ea)
+ *             Fixed entries counter. Added more
+ *             error codes check. Removed wprintf,
+ *             because it does not work in .17.
  */
 
 #include <ddk/ntddk.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-BYTE DirectoryEntry [(2 * MAX_PATH) + sizeof (OBJDIR_INFORMATION)];
+BYTE DirectoryEntry [32768];
 POBJDIR_INFORMATION pDirectoryEntry = (POBJDIR_INFORMATION) DirectoryEntry;
 
+static
+PCHAR
+STDCALL
+RawUszAsz (
+       PWCHAR  szU,
+       PCHAR   szA
+       )
+{
+       register PCHAR a = szA;
+       
+       while (*szU) {*szA++ = (CHAR) (0x00ff & * szU++);}
+       *szA = '\0';
+       return a;
+}
+
 
 static
 const char *
@@ -40,6 +59,10 @@ StatusToName (NTSTATUS Status)
                        return "STATUS_OBJECT_NAME_NOT_FOUND";
                case STATUS_PATH_SYNTAX_BAD:
                        return "STATUS_PATH_SYNTAX_BAD";
+               case STATUS_NO_MORE_ENTRIES:
+                       return "STATUS_NO_MORE_ENTRIES";
+               case STATUS_UNSUCCESSFUL:
+                       return "STATUS_UNSUCCESSFUL";
        }
        sprintf (RawValue, "0x%08lx", Status);
        return (const char *) RawValue;
@@ -127,7 +150,8 @@ int main(int argc, char* argv[])
        OBJECT_ATTRIBUTES       ObjectAttributes;
        NTSTATUS                Status;
        HANDLE                  DirectoryHandle;
-       ULONG                   BytesReturned = 0;
+       ULONG                   Context = 0;
+       ULONG                   ReturnLength = 0;
        ULONG                   EntryCount = 0;
        
        /* For expanding symbolic links */
@@ -187,6 +211,7 @@ int main(int argc, char* argv[])
                        );
                return EXIT_FAILURE;
        }
+       printf ("\n Directory of %s\n\n", argv[1]);
        /*
         * Enumerate each item in the directory.
         */
@@ -194,10 +219,10 @@ int main(int argc, char* argv[])
                        DirectoryHandle,
                        pDirectoryEntry,
                        sizeof DirectoryEntry,
-                       TRUE,
-                       TRUE,
-                       & BytesReturned,
-                       & EntryCount
+                       FALSE,/* ReturnSingleEntry */
+                       TRUE, /* RestartScan */
+                       & Context,
+                       & ReturnLength
                        );
        if (!NT_SUCCESS(Status))
        {
@@ -208,9 +233,12 @@ int main(int argc, char* argv[])
                NtClose (DirectoryHandle);
                return EXIT_FAILURE;
        }
-       wprintf (L"%d entries:\n", EntryCount);
-       while (STATUS_NO_MORE_ENTRIES != Status)
+       while (0 != pDirectoryEntry->ObjectTypeName.Length)
        {
+               CHAR ObjectNameA [MAX_PATH];
+               CHAR TypeNameA [MAX_PATH];
+               CHAR TargetNameA [MAX_PATH];
+               
                if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->ObjectTypeName.Buffer))
                {
                        if (TRUE == ExpandSymbolicLink (
@@ -220,40 +248,37 @@ int main(int argc, char* argv[])
                                        )
                                )
                        {
-                               wprintf (
-                                       L"%-16s %s -> %s\n",
-                                       pDirectoryEntry->ObjectTypeName.Buffer,
-                                       pDirectoryEntry->ObjectName.Buffer,
-                                       TargetObjectName.Buffer
+                               
+                               printf (
+                                       "%-16s %s -> %s\n",
+                                       RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
+                                       RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA),
+                                       RawUszAsz (TargetObjectName.Buffer, TargetNameA)
                                        );
                        }
                        else
                        {
-                               wprintf (
-                                       L"%-16s %s -> (error!)\n",
-                                       pDirectoryEntry->ObjectTypeName.Buffer,
-                                       pDirectoryEntry->ObjectName.Buffer
+                               printf (
+                                       "%-16s %s -> (error!)\n",
+                                       RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
+                                       RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
                                        );
                        }
                }
                else
                {
-                       wprintf (
-                               L"%-16s %s\n",
-                               pDirectoryEntry->ObjectTypeName.Buffer,
-                               pDirectoryEntry->ObjectName.Buffer
+                       printf (
+                               "%-16s %s\n",
+                               RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
+                               RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
                                );
                }
-               Status = NtQueryDirectoryObject (
-                               DirectoryHandle,
-                               pDirectoryEntry,
-                               sizeof DirectoryEntry,
-                               TRUE,
-                               FALSE,
-                               & BytesReturned,
-                               & EntryCount
-                               );
+               ++ EntryCount;
+               ++ pDirectoryEntry;
+               
+               
        }
+       printf ("\n\t%d object(s)\n", EntryCount);
        /*
         * Free any resource.
         */
index 78606ac..c20f8cc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dirobj.c,v 1.9 2000/10/22 16:36:52 ekohl Exp $
+/* $Id: dirobj.c,v 1.10 2001/05/01 21:43:45 ea Exp $
  *
  * COPYRIGHT:      See COPYING in the top level directory
  * PROJECT:        ReactOS kernel
@@ -81,29 +81,32 @@ NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
  *     NtQueryDirectoryObject
  * 
  * DESCRIPTION
- *     Reads information from a namespace directory.
+ *     Reads information from a directory in the system namespace.
  *     
  * ARGUMENTS
+ *     DirObjHandle
+ *             Handle, obtained with NtOpenDirectoryObject(), which
+ *             must grant DIRECTORY_QUERY access to the directory
+ *             object.
+ *             
  *     DirObjInformation (OUT)
  *             Buffer to hold the data read.
  *             
  *     BufferLength
  *             Size of the buffer in bytes.
  *             
- *     GetNextIndex
- *             If TRUE then set ObjectIndex to the index of the
- *             next object.
- *             If FALSE then set ObjectIndex to the number of
- *             objects in the directory.
+ *     ReturnSingleEntry
+ *             When TRUE, only 1 entry is written in DirObjInformation;
+ *             otherwise as many as will fit in the buffer.
  *             
- *     IgnoreInputIndex
+ *     RestartScan
  *             If TRUE start reading at index 0.
  *             If FALSE start reading at the index specified
- *             by object index.
+ *             by object index *ObjectIndex.
  *             
  *     ObjectIndex
  *             Zero based index into the directory, interpretation
- *             depends on IgnoreInputIndex and GetNextIndex.
+ *             depends on RestartScan.
  *             
  *     DataWritten (OUT)
  *             Caller supplied storage for the number of bytes
@@ -111,134 +114,183 @@ NTSTATUS STDCALL NtOpenDirectoryObject(PHANDLE DirectoryHandle,
  *
  * RETURN VALUE
  *     Status.
+ *
+ * REVISIONS
+ *     2001-05-01 (ea)
+ *             Changed 4th, and 5th parameter names after
+ *             G.Nebbett "WNT/W2k Native API Reference".
+ *             Mostly rewritten.
  */
 NTSTATUS STDCALL NtQueryDirectoryObject (IN HANDLE DirObjHandle,
                                         OUT POBJDIR_INFORMATION 
                                                    DirObjInformation, 
                                         IN ULONG BufferLength, 
-                                        IN BOOLEAN GetNextIndex, 
-                                        IN BOOLEAN IgnoreInputIndex
+                                        IN BOOLEAN ReturnSingleEntry,
+                                        IN BOOLEAN RestartScan
                                         IN OUT PULONG ObjectIndex,
                                         OUT PULONG DataWritten OPTIONAL)
 {
-   PDIRECTORY_OBJECT dir = NULL;
-   PLIST_ENTRY current_entry;
-   POBJECT_HEADER current;
-   ULONG i = 0;
-   ULONG EntriesToSkip;
-   NTSTATUS Status;
-   ULONG SpaceRequired;
-   ULONG FirstFree;
-   
-   DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
+    PDIRECTORY_OBJECT   dir = NULL;
+    PLIST_ENTRY         current_entry = NULL;
+    POBJECT_HEADER      current = NULL;
+    ULONG               i = 0;
+    NTSTATUS            Status = STATUS_SUCCESS;
+    DWORD              DirectoryCount = 0;
+    DWORD              DirectorySize = 0;
+    ULONG               SpaceLeft = BufferLength;
+    ULONG               SpaceRequired = 0;
+    ULONG               NameLength = 0;
+    ULONG               TypeNameLength = 0;
+    POBJDIR_INFORMATION current_odi = DirObjInformation;
+    PBYTE               FirstFree = (PBYTE) DirObjInformation;
+
+
+    DPRINT("NtQueryDirectoryObject(DirObjHandle %x)\n", DirObjHandle);
 
-   Status = ObReferenceObjectByHandle(DirObjHandle,
+    /* FIXME: if previous mode == user, use ProbeForWrite
+     * on user params. */
+
+    /* Reference the DIRECTORY_OBJECT */
+    Status = ObReferenceObjectByHandle(DirObjHandle,
                                      DIRECTORY_QUERY,
                                      ObDirectoryType,
                                      UserMode,
                                      (PVOID*)&dir,
                                      NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   /*
-    * Optionally, skip over some entries at the start of the directory
-    */
-   if (!IgnoreInputIndex)
-     {
+    if (!NT_SUCCESS(Status))
+      {
+        return (Status);
+      }
+    /* Check ObjectIndex is not NULL */
+    if (NULL == ObjectIndex)
+      {
+        return (STATUS_INVALID_PARAMETER);
+      }
+    /*
+     * Compute the number of directory entries
+     * and the size of the array (in bytes).
+     * One more entry marks the end of the array.
+     */
+    for (      current_entry = dir->head.Flink;
+               (current_entry != & dir->head);
+               current_entry = current_entry->Flink
+               )
+    {
+           ++ DirectoryCount;
+    }
+    DirectorySize = (DirectoryCount + 1) * sizeof (OBJDIR_INFORMATION);
+    if (DirectorySize >= SpaceLeft)
+    {
+       return (STATUS_BUFFER_TOO_SMALL);
+    }
+    /*
+     * Optionally, skip over some entries at the start of the directory
+     * (use *ObjectIndex value)
+     */
+    current_entry = dir->head.Flink;
+    if (FALSE == RestartScan)
+      {
+       /* RestartScan == FALSE */
+        register ULONG EntriesToSkip = *ObjectIndex;
+
        CHECKPOINT;
        
-       EntriesToSkip = *ObjectIndex;
-       i = 0;
-       current_entry = dir->head.Flink;
-       
-       while ((i < EntriesToSkip) && (current_entry != &dir->head))
+       for (   ;
+               ((EntriesToSkip ++) && (current_entry != & dir->head));
+               current_entry = current_entry->Flink
+               );
+       if ((EntriesToSkip) && (current_entry == & dir->head))
          {
-            current_entry = current_entry->Flink;
-            i++;
+            return (STATUS_INVALID_PARAMETER);
          }
-     }
-   else
-     {
-       current_entry = dir->head.Flink;
-       i = 0;
-     }
-   
-   /*
-    * Check if we have reached the end of the directory
-    */
-   if (current_entry != &dir->head)
-     {
-       *DataWritten = 0;
-       return(STATUS_NO_MORE_ENTRIES);
-     }
-   
-   /*
-    * Read the current entry into the buffer
-    */
-   FirstFree = sizeof(OBJDIR_INFORMATION);
-   
-   current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
-   
-   SpaceRequired = (wcslen(current->Name.Buffer) + 1) * 2;
-   SpaceRequired = SpaceRequired + 
-     ((wcslen(current->ObjectType->TypeName.Buffer) + 1) * 2);
-   SpaceRequired = SpaceRequired + sizeof(OBJDIR_INFORMATION);
-   
-   if (SpaceRequired <= BufferLength)
-     {
-       
-       DirObjInformation->ObjectName.Length = 
-         current->Name.Length;
-       DirObjInformation->ObjectName.MaximumLength = 
-         current->Name.Length;
-       DirObjInformation->ObjectName.Buffer = 
-         (((PVOID)DirObjInformation) + FirstFree);
-       FirstFree = FirstFree + (wcslen(current->Name.Buffer + 1) * 2);
-       wcscpy(DirObjInformation->ObjectName.Buffer,
-              current->Name.Buffer);
-               
-       DirObjInformation->ObjectTypeName.Length = 
-         current->ObjectType->TypeName.Length;
-       DirObjInformation->ObjectTypeName.MaximumLength = 
-         current->ObjectType->TypeName.Length;
-       DirObjInformation->ObjectName.Buffer = 
-         (((PVOID)DirObjInformation) + FirstFree);
-       FirstFree = FirstFree + 
-         (wcslen(current->ObjectType->TypeName.Buffer + 1) * 2);
-       wcscpy(DirObjInformation->ObjectTypeName.Buffer,
-              current->ObjectType->TypeName.Buffer);
-       
-       *DataWritten = SpaceRequired;
-       Status = STATUS_SUCCESS;
-     }
-   else
-     {
-       Status = STATUS_BUFFER_TOO_SMALL;
-     }
-   
-   /*
-    * Store into ObjectIndex
-    */
-   if (GetNextIndex)
-     {
-       *ObjectIndex = i + 1;
-     }
-   else
-     {
-       i = 0;
-       current_entry = dir->head.Flink;
-       while (current_entry != (&dir->head))
-         {
-            current_entry = current_entry->Flink;
-            i++;
-         }
-       *ObjectIndex = i;
-     }
-   
-   return(STATUS_SUCCESS);
+      }
+    /*
+     * Initialize the array of OBJDIR_INFORMATION.
+     */
+    RtlZeroMemory (FirstFree, DirectorySize);
+    /*
+     * Move FirstFree to point to the Unicode strings area
+     */
+    FirstFree += DirectorySize;
+    /*
+     * Compute how much space is left after allocating the
+     * array in the user buffer.
+     */
+    SpaceLeft -= DirectorySize;
+    /* Scan the directory */
+    do { 
+        /*
+         * Check if we reached the end of the directory.
+         */
+        if (current_entry == & dir->head)
+          {
+            /* Any data? */
+           if (i) break; /* DONE */
+           /* FIXME: better error handling here! */
+           return (STATUS_NO_MORE_ENTRIES);
+          }
+        /*
+        * Compute the current OBJECT_HEADER memory
+        * object's address.
+        */
+        current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
+        /*
+         * Compute the space required in the user buffer to copy
+         * the data from the current object:
+        *
+        * Name (WCHAR) 0 TypeName (WCHAR) 0
+         */
+       NameLength = (wcslen (current->Name.Buffer) * sizeof (WCHAR));
+       TypeNameLength = (wcslen (current->ObjectType->TypeName.Buffer) * sizeof (WCHAR));
+        SpaceRequired =
+            (NameLength + sizeof (WCHAR))
+            + (TypeNameLength + sizeof (WCHAR));
+       /*
+        * Check for free space in the user buffer.
+        */
+       if (SpaceRequired >= SpaceLeft)
+       {
+               return (STATUS_BUFFER_TOO_SMALL);
+       }
+        /*
+         * Copy the current directory entry's data into the buffer
+        * and update the OBJDIR_INFORMATION entry in the array.
+         */
+       /* --- Object's name --- */
+       current_odi->ObjectName.Length        = NameLength;
+       current_odi->ObjectName.MaximumLength = (NameLength + sizeof (WCHAR));
+       current_odi->ObjectName.Buffer        = (PWCHAR) FirstFree;
+       wcscpy ((PWCHAR) FirstFree, current->Name.Buffer);
+       FirstFree += (current_odi->ObjectName.MaximumLength);
+       /* --- Object type's name --- */
+       current_odi->ObjectTypeName.Length        = TypeNameLength;
+       current_odi->ObjectTypeName.MaximumLength = (TypeNameLength + sizeof (WCHAR));
+       current_odi->ObjectTypeName.Buffer        = (PWCHAR) FirstFree;
+       wcscpy ((PWCHAR) FirstFree, current->ObjectType->TypeName.Buffer);
+       FirstFree += (current_odi->ObjectTypeName.MaximumLength);
+       /* Next entry in the array */
+       ++ current_odi;
+       /* Decrease the space left count */     
+       SpaceLeft -= SpaceRequired;
+       /* Increase the object index number */
+       ++ i;
+       /* Next object in the directory */
+       current_entry = current_entry->Flink;
+
+    } while (FALSE == ReturnSingleEntry);
+    /*
+     * Store current index in ObjectIndex
+     */
+    *ObjectIndex = i;
+    /*
+     * Report to the caller how much bytes
+     * we wrote in the user buffer.
+     */
+    if (NULL != DataWritten) 
+      {
+        *DataWritten = (BufferLength - SpaceLeft);
+      }
+    return (STATUS_SUCCESS);
 }