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