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