Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

602 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992-2001 Microsoft Corporation
  3. Module Name:
  4. diskspace.cpp
  5. Abstract:
  6. WinDbg Extension Api
  7. Environment:
  8. Kernel Mode.
  9. Revision History:
  10. Mike McCracken (mmccr) 09/17/2001
  11. Prints out free space for a specifed volume
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. ULONG GetUNICODE_STRING(ULONG64 ul64Address, CHAR *pszBuffer, ULONG ulSize)
  16. {
  17. ULONG64 ul64Buffer = 0;
  18. ULONG ulLength = 0;
  19. ULONG ulBytesRead = 0;
  20. WCHAR wszLocalBuffer[MAX_PATH + 1] = {0};
  21. if ((!pszBuffer) || (!ulSize))
  22. {
  23. return E_FAIL;
  24. }
  25. if (GetFieldValue(ul64Address, "nt!_UNICODE_STRING",
  26. "Length", ulLength))
  27. {
  28. dprintf("Cannot get UNICODE_STRING length!\n");
  29. return E_FAIL;
  30. }
  31. if (GetFieldValue(ul64Address, "nt!_UNICODE_STRING",
  32. "Buffer", ul64Buffer))
  33. {
  34. dprintf("Cannot get UNICODE_STRING buffer!\n");
  35. return E_FAIL;
  36. }
  37. if (!ReadMemory(ul64Buffer,
  38. wszLocalBuffer,
  39. (ulLength < (MAX_PATH * 2)) ? ulLength : (MAX_PATH * 2),
  40. &ulBytesRead))
  41. {
  42. dprintf("Failed ReadMemory at 0x%I64x!\n", ul64Buffer);
  43. return E_FAIL;
  44. }
  45. wcstombs(pszBuffer, wszLocalBuffer, ulSize);
  46. return S_OK;
  47. }
  48. ULONG64 GetObpRootDirectoryObjectAddress()
  49. {
  50. ULONG64 ul64Temp = 0;
  51. ULONG64 ul64ObjRoot = 0;
  52. //Get the address of the pointer
  53. GetExpressionEx("nt!ObpRootDirectoryObject", &ul64Temp, NULL);
  54. //Get the value in the pointer
  55. ReadPtr(ul64Temp, &ul64ObjRoot);
  56. return ul64ObjRoot;
  57. }
  58. ULONG GetNumberOfHashBuckets()
  59. {
  60. FIELD_INFO Field = {(PUCHAR)"HashBuckets", NULL, 0, DBG_DUMP_FIELD_NO_CALLBACK_REQ , 0, NULL};
  61. SYM_DUMP_PARAM Sym = {sizeof(SYM_DUMP_PARAM), (PUCHAR)"nt!_OBJECT_DIRECTORY", DBG_DUMP_NO_PRINT, 0,
  62. NULL, NULL, NULL, sizeof (Field) / sizeof(FIELD_INFO), &Field};
  63. // Get the size of the HashBuckets member
  64. if (Ioctl(IG_DUMP_SYMBOL_INFO,
  65. &Sym,
  66. sizeof(Sym)))
  67. {
  68. dprintf("Failed to get size of HashBuckets!\n");
  69. return 0;
  70. }
  71. return (Field.size / (IsPtr64() ? 8 : 4));
  72. }
  73. ULONG GetObjectTypeName(ULONG64 ul64Object, CHAR *pszTypeName, ULONG ulSize)
  74. {
  75. ULONG ulTypeNameOffset = 0;
  76. ULONG ulObjectBodyOffset = 0;
  77. ULONG64 ul64Type = 0;
  78. // Get the offset of the object body
  79. if (GetFieldOffset("nt!_OBJECT_HEADER", "Body", &ulObjectBodyOffset))
  80. {
  81. dprintf("Cannot get ObjectBody offset!\n");
  82. return E_FAIL;
  83. }
  84. if (GetFieldValue(ul64Object - ulObjectBodyOffset, "nt!_OBJECT_HEADER", "Type", ul64Type))
  85. {
  86. dprintf("Failed to get Type value at 0x%I64x!\n", ul64Object);
  87. return E_FAIL;
  88. }
  89. if (GetFieldOffset("nt!_OBJECT_TYPE", "Name", &ulTypeNameOffset))
  90. {
  91. dprintf("Cannot get TypeName offset!\n");
  92. return E_FAIL;
  93. }
  94. return GetUNICODE_STRING(ul64Type + ulTypeNameOffset, pszTypeName, ulSize);
  95. }
  96. ULONG64 GetObjectChildDirectory(ULONG64 ul64Object)
  97. {
  98. CHAR szTypeName[MAX_PATH + 1] = {0};
  99. if (GetObjectTypeName(ul64Object, szTypeName, sizeof(szTypeName)))
  100. {
  101. return 0;
  102. }
  103. if (!_stricmp(szTypeName, "Directory"))
  104. {
  105. return ul64Object;
  106. }
  107. return 0;
  108. }
  109. ULONG GetRealDeviceForSymbolicLink(ULONG64 ul64Object, CHAR *pszDevicePath, ULONG ulSize)
  110. {
  111. CHAR szTypeName[MAX_PATH + 1] = {0};
  112. ULONG ulLinkTargetOffset = 0;
  113. if (GetObjectTypeName(ul64Object, szTypeName, sizeof(szTypeName)))
  114. {
  115. dprintf("Could not get TypeName for object in GetRealDeviceForSymbolicLink!\n");
  116. return E_FAIL;
  117. }
  118. if (_stricmp(szTypeName, "SymbolicLink"))
  119. {
  120. dprintf("Object in GetRealDeviceForSymbolicLink is a %s\n", szTypeName);
  121. return E_FAIL;
  122. }
  123. // Get the offset of the object body
  124. if (GetFieldOffset("nt!_OBJECT_SYMBOLIC_LINK", "LinkTarget", &ulLinkTargetOffset))
  125. {
  126. dprintf("Cannot get LinkTarget offset!\n");
  127. return E_FAIL;
  128. }
  129. return GetUNICODE_STRING(ul64Object + ulLinkTargetOffset, pszDevicePath, ulSize);
  130. }
  131. ULONG64 FindObjectByName(CHAR *ObjectPath, ULONG64 ul64StartPoint)
  132. {
  133. ULONG64 ul64ObjRoot = ul64StartPoint;
  134. ULONG64 ul64DirEntry = 0;
  135. ULONG ulNumberOfBuckets = 0;
  136. ULONG ulPointerSize = 4;
  137. ULONG ulHashOffset = 0;
  138. ULONG ulObjectBodyOffset = 0;
  139. ULONG ulNameInfoNameOffset = 0;
  140. ULONG i = 0;
  141. CHAR PathCopy[MAX_PATH + 1] = {0};
  142. CHAR *PathPtr = ObjectPath;
  143. if (!PathPtr)
  144. {
  145. return NULL;
  146. }
  147. while (PathPtr[0] == '\\')
  148. {
  149. PathPtr++;
  150. }
  151. //Copy the Path String
  152. strncpy(PathCopy, PathPtr, min(sizeof(PathCopy)-1, strlen(PathPtr)));
  153. if (ul64ObjRoot == 0)
  154. {
  155. // Get the address of the Root Directory Object
  156. ul64ObjRoot = GetObpRootDirectoryObjectAddress();
  157. if (!ul64ObjRoot)
  158. {
  159. dprintf("Could not get the address of the ObpRootDirectoryObject!\n");
  160. return NULL;
  161. }
  162. }
  163. if (ObjectPath[0] == '\0')
  164. {
  165. return ul64ObjRoot;
  166. }
  167. PathPtr = PathCopy;
  168. while ((PathPtr[0] != '\\') && (PathPtr[0] != '\0'))
  169. {
  170. PathPtr++;
  171. }
  172. if (PathPtr[0] == '\\')
  173. {
  174. PathPtr[0] = '\0';
  175. PathPtr++;
  176. }
  177. //Get the offset of the hashbuckets field in the _OBJECT_DIRECTORY structure
  178. if (GetFieldOffset("nt!_OBJECT_DIRECTORY", "HashBuckets", &ulHashOffset))
  179. {
  180. dprintf("Cannot get HashBuckets offset!\n");
  181. return NULL;
  182. }
  183. // Get the pointer size for our architecture
  184. ulPointerSize = (IsPtr64() ? 8 : 4);
  185. // Try to dynamically determine the number of HashBuckets in the _OBJECT_DIRECTORY structure
  186. ulNumberOfBuckets = GetNumberOfHashBuckets();
  187. if (!ulNumberOfBuckets)
  188. {
  189. ulNumberOfBuckets = 37; // From ob.h #define NUMBER_HASH_BUCKETS 37
  190. }
  191. // Get the offset of the object body
  192. if (GetFieldOffset("nt!_OBJECT_HEADER", "Body", &ulObjectBodyOffset))
  193. {
  194. dprintf("Cannot get ObjectBody offset!\n");
  195. return NULL;
  196. }
  197. // Get the offset of the object body
  198. if (GetFieldOffset("nt!_OBJECT_HEADER_NAME_INFO", "Name", &ulNameInfoNameOffset))
  199. {
  200. dprintf("Cannot get NameInfo Name Offset!\n");
  201. return NULL;
  202. }
  203. // Iterate through each bucket
  204. for (i=0; i < ulNumberOfBuckets; i++)
  205. {
  206. // Get the address of each _OBJECT_DIRECTORY_ENTRY in the HashBucket array
  207. if (ReadPointer(ul64ObjRoot + ulHashOffset + (i * ulPointerSize), &ul64DirEntry))
  208. {
  209. while (ul64DirEntry)
  210. {
  211. ULONG64 ul64Object = 0;
  212. ULONG64 ul64Header = 0;
  213. ULONG64 ul64NameInfo = 0;
  214. ULONG ulNameInfoOffset = 0;
  215. CHAR szObjName[MAX_PATH + 1] = {0};
  216. // Setup to point at our current object \
  217. // - this is actually a pointer to the body field of the _OBJECT_HEADER Structure
  218. if (GetFieldValue(ul64DirEntry, "nt!_OBJECT_DIRECTORY_ENTRY", "Object", ul64Object))
  219. {
  220. dprintf("Failed to get object value at 0x%I64x!\n", ul64DirEntry);
  221. break;
  222. }
  223. // Find the header for this object by subtracting the body (current) offset
  224. ul64Header = ul64Object - ulObjectBodyOffset;
  225. // Get the offset from the top of the header of the NameInfoObject
  226. if (GetFieldValue(ul64Header, "nt!_OBJECT_HEADER", "NameInfoOffset", ulNameInfoOffset))
  227. {
  228. dprintf("Failed to get NameInfoOffset pointer from objectheader at 0x%I64x!\n", ul64Header);
  229. break;
  230. }
  231. // If zero the object does not have one
  232. if (ulNameInfoOffset == 0)
  233. {
  234. break;
  235. }
  236. // Set our pointer to point to the _OBJECT_HEADER_NAME_INFO structure
  237. ul64NameInfo = ul64Header - ulNameInfoOffset;
  238. // Get the objects name
  239. if (GetUNICODE_STRING(ul64NameInfo + ulNameInfoNameOffset, szObjName, sizeof(szObjName)))
  240. {
  241. dprintf("Could Not Get Name\n");
  242. break;
  243. }
  244. if (!_stricmp(PathCopy, szObjName))
  245. {
  246. ULONG64 ul64NextDirectory = 0;
  247. if (PathPtr[0] == '\0')
  248. {
  249. return ul64Object;
  250. }
  251. ul64NextDirectory = GetObjectChildDirectory(ul64Object);
  252. return FindObjectByName(PathPtr, ul64NextDirectory);
  253. }
  254. //Get the next _OBJECT_DIRECTORY_ENTRY
  255. if (GetFieldValue(ul64DirEntry, "nt!_OBJECT_DIRECTORY_ENTRY", "ChainLink", ul64DirEntry))
  256. {
  257. dprintf("Failed to get next object value at 0x%I64x!\n", ul64Object);
  258. break;
  259. }
  260. } // while loop
  261. } // if statement
  262. } // for loop
  263. return NULL;
  264. }
  265. ULONG64 GetVPBPtrFromDeviceObject(ULONG64 ul64DeviceObject)
  266. {
  267. ULONG64 ul64VpbPtr = 0;
  268. // Get the offset from the top of the header of the NameInfoObject
  269. if (GetFieldValue(ul64DeviceObject, "nt!_DEVICE_OBJECT", "Vpb", ul64VpbPtr))
  270. {
  271. dprintf("Failed to get Vbp pointer from DeviceObject at 0x%I64x!\n", ul64DeviceObject);
  272. return NULL;
  273. }
  274. return ul64VpbPtr;
  275. }
  276. ULONG GetDeviceDriverString(ULONG64 ul64Device, CHAR *pszString, ULONG ulSize)
  277. {
  278. ULONG ulNameOffset = 0;
  279. ULONG64 ul64Driver = 0;
  280. if (GetFieldValue(ul64Device, "nt!_DEVICE_OBJECT", "DriverObject", ul64Driver))
  281. {
  282. dprintf("Failed to get DriverObject from Device pointer at 0x%I64x!\n", ul64Device);
  283. return E_FAIL;
  284. }
  285. // Get the offset of the DriverName in the _DRIVER_OBJECT
  286. if (GetFieldOffset("nt!_DRIVER_OBJECT", "DriverName", &ulNameOffset))
  287. {
  288. dprintf("Cannot get DriverName offset!\n");
  289. return E_FAIL;
  290. }
  291. return GetUNICODE_STRING(ul64Driver + ulNameOffset, pszString, ulSize);
  292. }
  293. VOID OutputData(ULONG ulBytesPerCluster,
  294. ULONG64 ul64TotalClusters,
  295. ULONG64 ul64FreeClusters)
  296. {
  297. ULONG64 ul64TotalBytes = ul64TotalClusters * ulBytesPerCluster;
  298. ULONG64 ul64FreeBytes = ul64FreeClusters * ulBytesPerCluster;
  299. dprintf(" Cluster Size %u KB\n", ulBytesPerCluster / 1024);
  300. dprintf(" Total Clusters %I64u KB\n", ul64TotalClusters);
  301. dprintf(" Free Clusters %I64u KB\n", ul64FreeClusters);
  302. dprintf(" Total Space %I64u GB (%I64u KB)\n",
  303. (ul64TotalBytes) / (0x40000000),
  304. (ul64TotalBytes) / (0x400));
  305. if (ul64FreeBytes > 0x40000000)
  306. {
  307. dprintf(" Free Space %I64f GB (%.2I64u MB)\n",
  308. (float)(ul64FreeBytes) / (0x40000000),
  309. (ul64FreeBytes) / (0x100000));
  310. }
  311. else if (ul64FreeBytes > 0x100000)
  312. {
  313. dprintf(" Free Space %I64f MB (%.2I64u KB)\n",
  314. (float)(ul64FreeBytes) / (0x100000),
  315. (ul64FreeBytes) / (0x400));
  316. }
  317. else
  318. {
  319. dprintf(" Free Space %I64u Bytes\n", ul64FreeBytes);
  320. }
  321. }
  322. ULONG GetAndOutputNTFSData(CHAR cDriveletter, ULONG64 ul64DevObj)
  323. {
  324. ULONG ulVCBOffset = 0;
  325. ULONG ulBytesPerCluster = 0;
  326. ULONG64 ul64TotalClusters = 0;
  327. ULONG64 ul64FreeClusters = 0;
  328. if (GetFieldOffset("ntfs!_VOLUME_DEVICE_OBJECT", "Vcb", &ulVCBOffset))
  329. {
  330. dprintf("Cannot get Vcb offset for NTFS Device!\n");
  331. return E_FAIL;
  332. }
  333. if (GetFieldValue(ul64DevObj + ulVCBOffset, "ntfs!_VCB", "BytesPerCluster", ulBytesPerCluster))
  334. {
  335. dprintf("Failed to get BytesPerCluster from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  336. return E_FAIL;
  337. }
  338. if (GetFieldValue(ul64DevObj + ulVCBOffset, "ntfs!_VCB", "TotalClusters", ul64TotalClusters))
  339. {
  340. dprintf("Failed to get TotalClusters from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  341. return E_FAIL;
  342. }
  343. if (GetFieldValue(ul64DevObj + ulVCBOffset, "ntfs!_VCB", "FreeClusters", ul64FreeClusters))
  344. {
  345. dprintf("Failed to get FreeClusters from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  346. return E_FAIL;
  347. }
  348. OutputData(ulBytesPerCluster, ul64TotalClusters, ul64FreeClusters);
  349. return S_OK;
  350. }
  351. ULONG GetAndOutputFatData(CHAR cDriveletter, ULONG64 ul64DevObj)
  352. {
  353. ULONG ulVCBOffset = 0;
  354. ULONG ulBytesPerSector = 0;
  355. ULONG ulSectorsPerCluster = 0;
  356. ULONG64 ul64TotalClusters = 0;
  357. ULONG64 ul64FreeClusters = 0;
  358. if (GetFieldOffset("fastfat!_VOLUME_DEVICE_OBJECT", "Vcb", &ulVCBOffset))
  359. {
  360. dprintf("Cannot get Vcb offset for FastFat Device!\n");
  361. return E_FAIL;
  362. }
  363. if (GetFieldValue(ul64DevObj + ulVCBOffset, "fastfat!_VCB", "Bpb.BytesPerSector", ulBytesPerSector))
  364. {
  365. dprintf("Failed to get BytesPerSector from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  366. return E_FAIL;
  367. }
  368. if (GetFieldValue(ul64DevObj + ulVCBOffset, "fastfat!_VCB", "Bpb.SectorsPerCluster", ulSectorsPerCluster))
  369. {
  370. dprintf("Failed to get SectorsPerCluster from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  371. return E_FAIL;
  372. }
  373. if (GetFieldValue(ul64DevObj + ulVCBOffset, "fastfat!_VCB", "AllocationSupport.NumberOfClusters", ul64TotalClusters))
  374. {
  375. dprintf("Failed to get TotalClusters from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  376. return E_FAIL;
  377. }
  378. if (GetFieldValue(ul64DevObj + ulVCBOffset, "fastfat!_VCB", "AllocationSupport.NumberOfFreeClusters", ul64FreeClusters))
  379. {
  380. dprintf("Failed to get FreeClusters from VCB at 0x%I64x!\n", ul64DevObj + ulVCBOffset);
  381. return E_FAIL;
  382. }
  383. OutputData(ulBytesPerSector * ulSectorsPerCluster, ul64TotalClusters, ul64FreeClusters);
  384. return S_OK;
  385. }
  386. DECLARE_API( diskspace )
  387. /*++
  388. Routine Description:
  389. Dumps free disk space for the specified volume
  390. Arguments:
  391. args - The volume letter of the drive on which you want the info
  392. Return Value:
  393. None
  394. --*/
  395. {
  396. ULONG ulReturn = S_OK;
  397. CHAR cVolume = args[0];
  398. CHAR szRootPath[MAX_PATH + 1] = {0};
  399. ULONG64 ul64Drive = 0;
  400. ULONG64 ul64Vpb = 0;
  401. INIT_API();
  402. // Make sure we have a valid drive letter as the first character.
  403. if (((cVolume < 'A') || (cVolume > 'z')) ||
  404. ((cVolume > 'Z') && (cVolume < 'a')))
  405. {
  406. dprintf("'%s' is not a valid drive specification!\n", args);
  407. ulReturn = E_FAIL;
  408. goto exit;
  409. }
  410. // Make sure this is likely to be a valid param in that it is
  411. // followed by a space of a colon.
  412. if ((args[1] != ' ') && (args[1] != ':') && (args[1] != '\0'))
  413. {
  414. dprintf("'%s' is not a valid drive specification!\n", args);
  415. ulReturn = E_FAIL;
  416. goto exit;
  417. }
  418. sprintf(szRootPath, "\\GLOBAL??\\%c:", cVolume);
  419. dprintf("Checking Free Space for %c: ", cVolume);
  420. ul64Drive = FindObjectByName(szRootPath, 0);
  421. if (!ul64Drive)
  422. {
  423. dprintf("\nFailed to find volume %c:!\n", cVolume);
  424. ulReturn = E_FAIL;
  425. goto exit;
  426. }
  427. GetRealDeviceForSymbolicLink(ul64Drive, szRootPath, sizeof(szRootPath));
  428. if (strstr(_strlwr(szRootPath), "cdrom"))
  429. {
  430. dprintf("\n%c: is a CDROM drive. This function is not supported!\n", cVolume);
  431. ulReturn = E_FAIL;
  432. goto exit;
  433. }
  434. dprintf("..");
  435. ul64Drive = FindObjectByName(szRootPath, 0);
  436. dprintf("..");
  437. if (GetFieldValue(ul64Drive, "nt!_DEVICE_OBJECT", "Vpb", ul64Vpb))
  438. {
  439. dprintf("Failed to get Vbp pointer from DeviceObject at 0x%I64x!\n", ul64Drive);
  440. ulReturn = E_FAIL;
  441. goto exit;
  442. }
  443. dprintf("..");
  444. if (GetFieldValue(ul64Vpb, "nt!_VPB", "DeviceObject", ul64Drive))
  445. {
  446. dprintf("Failed to get DeviceObject from VBP pointer at 0x%I64x!\n", ul64Vpb);
  447. ulReturn = E_FAIL;
  448. goto exit;
  449. }
  450. dprintf("..");
  451. if (GetDeviceDriverString(ul64Drive, szRootPath, sizeof(szRootPath)))
  452. {
  453. dprintf("Failed to Get Driver String From Device at 0x%I64x!\n", ul64Drive);
  454. ulReturn = E_FAIL;
  455. goto exit;
  456. }
  457. dprintf("..\n");
  458. if (strstr(_strlwr(szRootPath), "ntfs"))
  459. {
  460. GetAndOutputNTFSData(cVolume, ul64Drive);
  461. }
  462. else if (strstr(_strlwr(szRootPath), "fastfat"))
  463. {
  464. GetAndOutputFatData(cVolume, ul64Drive);
  465. }
  466. else if (strstr(_strlwr(szRootPath), "cdfs"))
  467. {
  468. dprintf("This extension does not support the cdfs filesystem!\n");
  469. }
  470. else
  471. {
  472. dprintf("Unable to determine Volume Type for %s!\n", szRootPath);
  473. }
  474. exit:
  475. EXIT_API();
  476. return ulReturn;
  477. }