[HEADERS]
[reactos.git] / rosapps / applications / sysutils / 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 #define WIN32_NO_STATUS
21 #include <windows.h>
22 #include <stdlib.h>
23 #include <ntndk.h>
24 #include <stdio.h>
25
26 #define MAX_DIR_ENTRY 256
27
28
29 static
30 PCHAR
31 WINAPI
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 WINAPI
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 WINAPI
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_OBJECT_PATH_SYNTAX_BAD:
79 return "STATUS_PATH_SYNTAX_BAD";
80 case STATUS_NO_MORE_ENTRIES:
81 return "STATUS_NO_MORE_ENTRIES";
82 case STATUS_MORE_ENTRIES:
83 return "STATUS_MORE_ENTRIES";
84 case STATUS_ACCESS_DENIED:
85 return "STATUS_ACCESS_DENIED";
86 case STATUS_UNSUCCESSFUL:
87 return "STATUS_UNSUCCESSFUL";
88 case STATUS_INVALID_HANDLE:
89 return "STATUS_INVALID_HANDLE";
90 }
91 sprintf (RawValue, "0x%08lx", Status);
92 return (const char *) RawValue;
93 }
94
95
96 BOOL
97 WINAPI
98 ExpandSymbolicLink (
99 IN PUNICODE_STRING DirectoryName,
100 IN PUNICODE_STRING SymbolicLinkName,
101 IN OUT PUNICODE_STRING TargetObjectName
102 )
103 {
104 NTSTATUS Status;
105 HANDLE hSymbolicLink;
106 OBJECT_ATTRIBUTES oa;
107 UNICODE_STRING Path;
108 WCHAR PathBuffer [MAX_PATH];
109 ULONG DataWritten = 0;
110
111
112 Path.Buffer = PathBuffer;
113 Path.Length = 0;
114 Path.MaximumLength = sizeof PathBuffer;
115
116 RtlCopyUnicodeString (& Path, DirectoryName);
117 if (L'\\' != Path.Buffer [(Path.Length / sizeof Path.Buffer[0]) - 1])
118 {
119 RtlAppendUnicodeToString (& Path, L"\\");
120 }
121 RtlAppendUnicodeStringToString (& Path, SymbolicLinkName);
122
123 oa.Length = sizeof (OBJECT_ATTRIBUTES);
124 oa.ObjectName = & Path;
125 oa.Attributes = 0; /* OBJ_CASE_INSENSITIVE; */
126 oa.RootDirectory = NULL;
127 oa.SecurityDescriptor = NULL;
128 oa.SecurityQualityOfService = NULL;
129
130 Status = NtOpenSymbolicLinkObject(
131 & hSymbolicLink,
132 SYMBOLIC_LINK_QUERY, /* 0x20001 */
133 & oa
134 );
135
136 if (!NT_SUCCESS(Status))
137 {
138 printf (
139 "Failed to open SymbolicLink object (Status: %s)\n",
140 StatusToName (Status)
141 );
142 return FALSE;
143 }
144 TargetObjectName->Length = TargetObjectName->MaximumLength;
145 memset (
146 TargetObjectName->Buffer,
147 0,
148 TargetObjectName->MaximumLength
149 );
150 Status = NtQuerySymbolicLinkObject(
151 hSymbolicLink,
152 TargetObjectName,
153 & DataWritten
154 );
155 if (!NT_SUCCESS(Status))
156 {
157 printf (
158 "Failed to query SymbolicLink object (Status: %s)\n",
159 StatusToName (Status)
160 );
161 NtClose (hSymbolicLink);
162 return FALSE;
163 }
164 NtClose (hSymbolicLink);
165 return TRUE;
166 }
167
168
169 BOOL
170 WINAPI
171 ListDirectory (
172 IN PUNICODE_STRING DirectoryNameW,
173 IN BOOL Recurse
174 )
175 {
176 CHAR DirectoryNameA [MAX_PATH];
177 OBJECT_ATTRIBUTES ObjectAttributes;
178 NTSTATUS Status;
179 HANDLE DirectoryHandle;
180 BYTE DirectoryEntry [512];
181 POBJECT_DIRECTORY_INFORMATION pDirectoryEntry = (POBJECT_DIRECTORY_INFORMATION) DirectoryEntry;
182 POBJECT_DIRECTORY_INFORMATION pDirectoryEntries = (POBJECT_DIRECTORY_INFORMATION) DirectoryEntry;
183 ULONG Context = 0;
184 ULONG ReturnLength = 0;
185 ULONG EntryCount = 0;
186
187 /* For expanding symbolic links */
188 WCHAR TargetName [2 * MAX_PATH];
189 UNICODE_STRING TargetObjectName = {
190 sizeof TargetName,
191 sizeof TargetName,
192 TargetName
193 };
194
195 /* Convert to ANSI the directory's name */
196 RawUszAsz (DirectoryNameW->Buffer, DirectoryNameA);
197 /*
198 * Prepare parameters for next call.
199 */
200 InitializeObjectAttributes (
201 & ObjectAttributes,
202 DirectoryNameW,
203 0,
204 NULL,
205 NULL
206 );
207 /*
208 * Try opening the directory.
209 */
210 Status = NtOpenDirectoryObject (
211 & DirectoryHandle,
212 DIRECTORY_QUERY,
213 & ObjectAttributes
214 );
215 if (!NT_SUCCESS(Status))
216 {
217 printf (
218 "Failed to open directory object \"%s\" (Status: %s)\n",
219 DirectoryNameA,
220 StatusToName (Status)
221 );
222 return (FALSE);
223 }
224 printf ("\n Directory of %s\n\n", DirectoryNameA);
225
226 for(;;)
227 {
228 /*
229 * Enumerate each item in the directory.
230 */
231 Status = NtQueryDirectoryObject (
232 DirectoryHandle,
233 pDirectoryEntries,
234 sizeof DirectoryEntry,
235 FALSE,/* ReturnSingleEntry */
236 FALSE, /* RestartScan */
237 & Context,
238 & ReturnLength
239 );
240 if (!NT_SUCCESS(Status) && Status != STATUS_NO_MORE_ENTRIES)
241 {
242 printf (
243 "Failed to query directory object (Status: %s)\n",
244 StatusToName (Status)
245 );
246 NtClose (DirectoryHandle);
247 return (FALSE);
248 }
249 if (Status == STATUS_NO_MORE_ENTRIES)
250 {
251 break;
252 }
253 pDirectoryEntry = pDirectoryEntries;
254 while (EntryCount < Context)
255 {
256 CHAR ObjectNameA [MAX_PATH];
257 CHAR TypeNameA [MAX_PATH];
258 CHAR TargetNameA [MAX_PATH];
259
260 if (0 == wcscmp (L"SymbolicLink", pDirectoryEntry->TypeName.Buffer))
261 {
262 if (TRUE == ExpandSymbolicLink (
263 DirectoryNameW,
264 & pDirectoryEntry->Name,
265 & TargetObjectName
266 )
267 )
268 {
269
270 printf (
271 "%-16s %s -> %s\n",
272 RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
273 RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA),
274 RawUszAsz (TargetObjectName.Buffer, TargetNameA)
275 );
276 }
277 else
278 {
279 printf (
280 "%-16s %s -> (error!)\n",
281 RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
282 RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA)
283 );
284 }
285 }
286 else
287 {
288 printf (
289 "%-16s %s\n",
290 RawUszAsz (pDirectoryEntry->TypeName.Buffer, TypeNameA),
291 RawUszAsz (pDirectoryEntry->Name.Buffer, ObjectNameA)
292 );
293 }
294 ++ pDirectoryEntry;
295 ++ EntryCount;
296 }
297 };
298 printf ("\n\t%lu object(s)\n", EntryCount);
299 /*
300 * Free any resource.
301 */
302 NtClose (DirectoryHandle);
303 /*
304 * Recurse into, if required so.
305 */
306 if (FALSE != Recurse)
307 {
308 pDirectoryEntry = (POBJECT_DIRECTORY_INFORMATION) DirectoryEntry;
309 while (0 != pDirectoryEntry->TypeName.Length)
310 {
311 if (0 == wcscmp (L"Directory", pDirectoryEntry->TypeName.Buffer))
312 {
313 WCHAR CurrentName [MAX_PATH];
314 UNICODE_STRING CurrentDirectory;
315
316 CurrentName [0] = L'\0';
317 wcscpy (CurrentName, DirectoryNameW->Buffer);
318 if (wcslen (CurrentName) > 1)
319 {
320 wcscat (CurrentName, L"\\");
321 }
322 wcscat (CurrentName, pDirectoryEntry->Name.Buffer);
323 RtlInitUnicodeString (& CurrentDirectory, CurrentName);
324 ListDirectory (& CurrentDirectory, Recurse);
325 }
326 ++ pDirectoryEntry;
327 }
328 }
329 return (TRUE);
330 }
331
332
333 int main(int argc, char* argv[])
334 {
335 WCHAR DirectoryNameW [MAX_PATH];
336 UNICODE_STRING DirectoryName;
337 BOOL Recurse = FALSE;
338
339 /*
340 * Check user arguments.
341 */
342 switch (argc)
343 {
344 case 2:
345 RawAszUsz (argv[1], DirectoryNameW);
346 break;
347 case 3:
348 if (strcmp (argv[1], "-r"))
349 {
350 fprintf (
351 stderr,
352 "%s: unknown option '%s'.\n",
353 argv [0], argv[1]
354 );
355 return EXIT_FAILURE;
356 }
357 RawAszUsz (argv[2], DirectoryNameW);
358 Recurse = TRUE;
359 break;
360 default:
361 fprintf (
362 stderr,
363 "\nUsage: %s [-r] directory\n\n"
364 " -r recurse\n"
365 " directory a directory name in the system namespace\n\n",
366 argv [0]
367 );
368 return EXIT_FAILURE;
369 }
370 /*
371 * List the directory.
372 */
373 RtlInitUnicodeString (& DirectoryName, DirectoryNameW);
374 return (FALSE == ListDirectory (& DirectoryName, Recurse))
375 ? EXIT_FAILURE
376 : EXIT_SUCCESS;
377 }
378
379
380 /* EOF */