Added -r switch to objdir to recurse the system name space.
[reactos.git] / reactos / apps / utils / objdir / objdir.c
1 /* $Id: objdir.c,v 1.7 2001/05/02 20:50:06 ea Exp $
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 printf (
233 "Failed to query directory object (Status: %s)\n",
234 StatusToName (Status)
235 );
236 NtClose (DirectoryHandle);
237 return (FALSE);
238 }
239 while (0 != pDirectoryEntry->ObjectTypeName.Length)
240 {
241 CHAR ObjectNameA [MAX_PATH];
242 CHAR TypeNameA [MAX_PATH];
243 CHAR TargetNameA [MAX_PATH];
244
245 if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->ObjectTypeName.Buffer))
246 {
247 if (TRUE == ExpandSymbolicLink (
248 DirectoryNameW,
249 & pDirectoryEntry->ObjectName,
250 & TargetObjectName
251 )
252 )
253 {
254
255 printf (
256 "%-16s %s -> %s\n",
257 RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
258 RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA),
259 RawUszAsz (TargetObjectName.Buffer, TargetNameA)
260 );
261 }
262 else
263 {
264 printf (
265 "%-16s %s -> (error!)\n",
266 RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
267 RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
268 );
269 }
270 }
271 else
272 {
273 printf (
274 "%-16s %s\n",
275 RawUszAsz (pDirectoryEntry->ObjectTypeName.Buffer, TypeNameA),
276 RawUszAsz (pDirectoryEntry->ObjectName.Buffer, ObjectNameA)
277 );
278 }
279 ++ EntryCount;
280 ++ pDirectoryEntry;
281 }
282 printf ("\n\t%d object(s)\n", EntryCount);
283 /*
284 * Free any resource.
285 */
286 NtClose (DirectoryHandle);
287 /*
288 * Recurse into, if required so.
289 */
290 if (FALSE != Recurse)
291 {
292 pDirectoryEntry = (POBJDIR_INFORMATION) DirectoryEntry;
293 while (0 != pDirectoryEntry->ObjectTypeName.Length)
294 {
295 if (0 == wcscmp (L"Directory", pDirectoryEntry->ObjectTypeName.Buffer))
296 {
297 WCHAR CurrentName [MAX_PATH];
298 UNICODE_STRING CurrentDirectory;
299
300 CurrentName [0] = L'\0';
301 wcscpy (CurrentName, DirectoryNameW->Buffer);
302 if (wcslen (CurrentName) > 1)
303 {
304 wcscat (CurrentName, L"\\");
305 }
306 wcscat (CurrentName, pDirectoryEntry->ObjectName.Buffer);
307 RtlInitUnicodeString (& CurrentDirectory, CurrentName);
308 ListDirectory (& CurrentDirectory, Recurse);
309 }
310 ++ pDirectoryEntry;
311 }
312 }
313 return (TRUE);
314 }
315
316
317 int main(int argc, char* argv[])
318 {
319 WCHAR DirectoryNameW [MAX_PATH];
320 UNICODE_STRING DirectoryName;
321 BOOL Recurse = FALSE;
322
323 /*
324 * Check user arguments.
325 */
326 switch (argc)
327 {
328 case 2:
329 RawAszUsz (argv[1], DirectoryNameW);
330 break;
331 case 3:
332 if (strcmp (argv[1], "-r"))
333 {
334 fprintf (
335 stderr,
336 "%s: unknown option '%s'.\n",
337 argv [0], argv[1]
338 );
339 return EXIT_FAILURE;
340 }
341 RawAszUsz (argv[2], DirectoryNameW);
342 Recurse = TRUE;
343 break;
344 default:
345 fprintf (
346 stderr,
347 "\nUsage: %s [-r] directory\n\n"
348 " -r recurse\n"
349 " directory a directory name in the system namespace\n\n",
350 argv [0]
351 );
352 return EXIT_FAILURE;
353 }
354 /*
355 * List the directory.
356 */
357 RtlInitUnicodeString (& DirectoryName, DirectoryNameW);
358 return (FALSE == ListDirectory (& DirectoryName, Recurse))
359 ? EXIT_FAILURE
360 : EXIT_SUCCESS;
361 }
362
363
364 /* EOF */