minor corrections by M.Taguchi
[reactos.git] / reactos / apps / utils / objdir / objdir.c
1 /* $Id: objdir.c,v 1.13 2003/11/11 17:00:41 ekohl 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_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_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(DIRECTORY_BASIC_INFORMATION)];
175 PDIRECTORY_BASIC_INFORMATION pDirectoryEntry = (PDIRECTORY_BASIC_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%lu 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 = (PDIRECTORY_BASIC_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 */