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 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 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 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 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 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 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