:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / apps / utils / objdir / objdir.c
1 /* $Id$
2  *
3  * DESCRIPTION: Object Manager Simple Explorer
4  * PROGRAMMER:  David Welch
5  * REVISIONS
6  *      2000-04-30 (ea)
7  *              Added directory enumeration.
8  *              (tested under nt4sp4/x86)
9  *      2000-08-11 (ea)
10  *              Added symbolic link expansion.
11  *              (tested under nt4sp4/x86)
12  *      2001-05-01 (ea)
13  *              Fixed entries counter. Added more
14  *              error codes check. Removed wprintf,
15  *              because it does not work in .17.
16  *      2001-05-02 (ea)
17  *              Added -r option.
18  */
19
20 #include <ddk/ntddk.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #define MAX_DIR_ENTRY 256
27
28
29 static
30 PCHAR
31 STDCALL
32 RawUszAsz (
33         PWCHAR  szU,
34         PCHAR   szA
35         )
36 {
37         register PCHAR a = szA;
38         
39         while (*szU) {*szA++ = (CHAR) (0x00ff & * szU++);}
40         *szA = '\0';
41         return a;
42 }
43
44
45 static
46 PWCHAR
47 STDCALL
48 RawAszUsz (
49         PCHAR   szA,
50         PWCHAR  szW
51         )
52 {
53         register PWCHAR w = szW;
54         
55         while (*szA) {*szW++ = (WCHAR) *szA++;}
56         *szW = L'\0';
57         return w;
58 }
59
60
61 static
62 const char *
63 STDCALL
64 StatusToName (NTSTATUS Status)
65 {
66         static char RawValue [16];
67         
68         switch (Status)
69         {
70                 case STATUS_BUFFER_TOO_SMALL:
71                         return "STATUS_BUFFER_TOO_SMALL";
72                 case STATUS_INVALID_PARAMETER:
73                         return "STATUS_INVALID_PARAMETER";
74                 case STATUS_OBJECT_NAME_INVALID:
75                         return "STATUS_OBJECT_NAME_INVALID";
76                 case STATUS_OBJECT_NAME_NOT_FOUND:
77                         return "STATUS_OBJECT_NAME_NOT_FOUND";
78                 case STATUS_PATH_SYNTAX_BAD:
79                         return "STATUS_PATH_SYNTAX_BAD";
80                 case STATUS_NO_MORE_ENTRIES:
81                         return "STATUS_NO_MORE_ENTRIES";
82                 case STATUS_UNSUCCESSFUL:
83                         return "STATUS_UNSUCCESSFUL";
84         }
85         sprintf (RawValue, "0x%08lx", Status);
86         return (const char *) RawValue;
87 }
88
89
90 BOOL
91 STDCALL
92 ExpandSymbolicLink (
93         IN      PUNICODE_STRING DirectoryName,
94         IN      PUNICODE_STRING SymbolicLinkName,
95         IN OUT  PUNICODE_STRING TargetObjectName
96         )
97 {
98         NTSTATUS                Status;
99         HANDLE                  hSymbolicLink;
100         OBJECT_ATTRIBUTES       oa;
101         UNICODE_STRING          Path;
102         WCHAR                   PathBuffer [MAX_PATH];
103         ULONG                   DataWritten = 0;
104
105
106         Path.Buffer = PathBuffer;
107         Path.Length = 0;
108         Path.MaximumLength = sizeof PathBuffer;
109         
110         RtlCopyUnicodeString (& Path, DirectoryName);
111         if (L'\\' != Path.Buffer [(Path.Length / sizeof Path.Buffer[0]) - 1])
112         {
113                 RtlAppendUnicodeToString (& Path, L"\\");
114         }
115         RtlAppendUnicodeStringToString (& Path, SymbolicLinkName);
116
117         oa.Length                       = sizeof (OBJECT_ATTRIBUTES);
118         oa.ObjectName                   = & Path;
119         oa.Attributes                   = 0; /* OBJ_CASE_INSENSITIVE; */
120         oa.RootDirectory                = NULL;
121         oa.SecurityDescriptor           = NULL;
122         oa.SecurityQualityOfService     = NULL;
123
124         Status = NtOpenSymbolicLinkObject(
125                         & hSymbolicLink,
126                         SYMBOLIC_LINK_QUERY,    /* 0x20001 */
127                         & oa
128                         );
129
130         if (!NT_SUCCESS(Status))
131         {
132                 printf (
133                         "Failed to open SymbolicLink object (Status: %s)\n",
134                         StatusToName (Status)
135                         );
136                 return FALSE;
137         }
138         TargetObjectName->Length = TargetObjectName->MaximumLength;
139         memset (
140                 TargetObjectName->Buffer,
141                 0,
142                 TargetObjectName->MaximumLength
143                 );
144         Status = NtQuerySymbolicLinkObject(
145                         hSymbolicLink,
146                         TargetObjectName,
147                         & DataWritten
148                         );
149         if (!NT_SUCCESS(Status))
150         {
151                 printf (
152                         "Failed to query SymbolicLink object (Status: %s)\n",
153                         StatusToName (Status)
154                         );
155                 NtClose (hSymbolicLink);
156                 return FALSE;
157         }
158         NtClose (hSymbolicLink);
159         return TRUE;
160 }
161
162
163 BOOL
164 STDCALL
165 ListDirectory (
166         IN      PUNICODE_STRING DirectoryNameW,
167         IN      BOOL            Recurse
168         )
169 {
170         CHAR                    DirectoryNameA [MAX_PATH];
171         OBJECT_ATTRIBUTES       ObjectAttributes;
172         NTSTATUS                Status;
173         HANDLE                  DirectoryHandle;
174         BYTE                    DirectoryEntry [MAX_DIR_ENTRY * sizeof(OBJDIR_INFORMATION)];
175         POBJDIR_INFORMATION     pDirectoryEntry = (POBJDIR_INFORMATION) DirectoryEntry;
176         ULONG                   Context = 0;
177         ULONG                   ReturnLength = 0;
178         ULONG                   EntryCount = 0;
179         
180         /* For expanding symbolic links */
181         WCHAR                   TargetName [2 * MAX_PATH];
182         UNICODE_STRING          TargetObjectName = {
183                                         sizeof TargetName,
184                                         sizeof TargetName,
185                                         TargetName
186                                 };
187
188         /* Convert to ANSI the directory's name */
189         RawUszAsz (DirectoryNameW->Buffer, DirectoryNameA);
190         /*
191          * Prepare parameters for next call.
192          */
193         InitializeObjectAttributes (
194                 & ObjectAttributes,
195                 DirectoryNameW,
196                 0,
197                 NULL,
198                 NULL
199                 );
200         /*
201          * Try opening the directory.
202          */
203         Status = NtOpenDirectoryObject (
204                         & DirectoryHandle,
205                         DIRECTORY_QUERY,
206                         & ObjectAttributes
207                         );
208         if (!NT_SUCCESS(Status))
209         {
210                 printf (
211                         "Failed to open directory object \"%s\" (Status: %s)\n",
212                         DirectoryNameA,
213                         StatusToName (Status)
214                         );
215                 return (FALSE);
216         }
217         printf ("\n Directory of %s\n\n", DirectoryNameA);
218         /*
219          * Enumerate each item in the directory.
220          */
221         Status = NtQueryDirectoryObject (
222                         DirectoryHandle,
223                         pDirectoryEntry,
224                         sizeof DirectoryEntry,
225                         FALSE,/* ReturnSingleEntry */
226                         TRUE, /* RestartScan */
227                         & Context,
228                         & ReturnLength
229                         );
230         if (!NT_SUCCESS(Status))
231         {
232                 if (STATUS_NO_MORE_ENTRIES == Status)
233                 {
234                         NtClose (DirectoryHandle);
235                         return TRUE;
236                 }
237                 printf (
238                         "Failed to query directory object (Status: %s)\n",
239                         StatusToName (Status)
240                         );
241                 NtClose (DirectoryHandle);
242                 return (FALSE);
243         }
244         while (0 != pDirectoryEntry->ObjectTypeName.Length)
245         {
246                 CHAR ObjectNameA [MAX_PATH];
247                 CHAR TypeNameA [MAX_PATH];
248                 CHAR TargetNameA [MAX_PATH];
249                 
250                 if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->ObjectTypeName.Buffer))
251                 {
252                         if (TRUE == ExpandSymbolicLink (
253                                         DirectoryNameW,
254                                         & pDirectoryEntry->ObjectName,
255                                         & TargetObjectName
256                                         )
257                                 )
258                         {
259                                 
260                                 printf (
261                                         "%-16s %s -> %s\n",
262                                         RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
263                                         RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA),
264                                         RawUszAsz (TargetObjectName.Buffer, TargetNameA)
265                                         );
266                         }
267                         else
268                         {
269                                 printf (
270                                         "%-16s %s -> (error!)\n",
271                                         RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
272                                         RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
273                                         );
274                         }
275                 }
276                 else
277                 {
278                         printf (
279                                 "%-16s %s\n",
280                                 RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
281                                 RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
282                                 );
283                 }
284                 ++ EntryCount;
285                 ++ pDirectoryEntry;
286         }
287         printf ("\n\t%d object(s)\n", EntryCount);
288         /*
289          * Free any resource.
290          */
291         NtClose (DirectoryHandle);
292         /*
293          * Recurse into, if required so.
294          */
295         if (FALSE != Recurse)
296         {
297                 pDirectoryEntry = (POBJDIR_INFORMATION) DirectoryEntry;
298                 while (0 != pDirectoryEntry->ObjectTypeName.Length)
299                 {
300                         if (0 == wcscmp (L"Directory", pDirectoryEntry->ObjectTypeName.Buffer))
301                         {
302                                 WCHAR           CurrentName [MAX_PATH];
303                                 UNICODE_STRING  CurrentDirectory;
304
305                                 CurrentName [0] = L'\0';
306                                 wcscpy (CurrentName, DirectoryNameW->Buffer);
307                                 if (wcslen (CurrentName) > 1)
308                                 {
309                                         wcscat (CurrentName, L"\\");
310                                 }
311                                 wcscat (CurrentName, pDirectoryEntry->ObjectName.Buffer);
312                                 RtlInitUnicodeString (& CurrentDirectory, CurrentName);
313                                 ListDirectory (& CurrentDirectory, Recurse);
314                         }
315                         ++ pDirectoryEntry;
316                 }
317         }
318         return (TRUE);
319 }
320
321
322 int main(int argc, char* argv[])
323 {
324         WCHAR           DirectoryNameW [MAX_PATH];
325         UNICODE_STRING  DirectoryName;
326         BOOL            Recurse = FALSE;
327
328         /*
329          * Check user arguments.
330          */
331         switch (argc)
332         {
333         case 2:
334                 RawAszUsz (argv[1], DirectoryNameW);
335                 break;
336         case 3:
337                 if (strcmp (argv[1], "-r"))
338                 {
339                         fprintf (
340                                 stderr,
341                                 "%s: unknown option '%s'.\n",
342                                 argv [0], argv[1]
343                                 );
344                         return EXIT_FAILURE;
345                 }
346                 RawAszUsz (argv[2], DirectoryNameW);
347                 Recurse = TRUE; 
348                 break;
349         default:
350                 fprintf (
351                         stderr,
352                         "\nUsage: %s [-r] directory\n\n"
353                         "  -r          recurse\n"
354                         "  directory   a directory name in the system namespace\n\n",
355                         argv [0]
356                         );
357                 return EXIT_FAILURE;
358         }
359         /*
360          * List the directory.
361          */
362         RtlInitUnicodeString (& DirectoryName, DirectoryNameW);
363         return (FALSE == ListDirectory (& DirectoryName, Recurse))
364                 ? EXIT_FAILURE
365                 : EXIT_SUCCESS;
366 }
367
368
369 /* EOF */