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.

452 lines
10 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. sfspace.c
  5. Abstract:
  6. sfspace calculates the amount of space required for shell folders in a clean install of
  7. Windows 2000 and outputs the results in a form which can be copied into win95upg.inf.
  8. Author:
  9. Marc R. Whitten (marcw) 24-Mar-1999
  10. Revision History:
  11. <full name> (<alias>) <date> <comments>
  12. --*/
  13. #include "pch.h"
  14. #include "shlobj.h"
  15. HANDLE g_hHeap;
  16. HINSTANCE g_hInst;
  17. BOOL WINAPI MigUtil_Entry (HINSTANCE, DWORD, PVOID);
  18. //BOOL WINAPI MemDb_Entry (HINSTANCE, DWORD, PVOID);
  19. #define SFLIST \
  20. DEFMAC(AppData, CSIDL_APPDATA) \
  21. DEFMAC(Cache, CSIDL_INTERNET_CACHE) \
  22. DEFMAC(Cookies, CSIDL_COOKIES) \
  23. DEFMAC(Desktop, CSIDL_DESKTOPDIRECTORY) \
  24. DEFMAC(Favorites, CSIDL_FAVORITES) \
  25. DEFMAC(History, CSIDL_HISTORY) \
  26. DEFMAC(Local AppData, CSIDL_LOCAL_APPDATA) \
  27. DEFMAC(Local Settings, CSIDL_LOCAL_APPDATA) \
  28. DEFMAC(My Pictures, CSIDL_MYPICTURES) \
  29. DEFMAC(NetHood, CSIDL_NETHOOD) \
  30. DEFMAC(Personal, CSIDL_PERSONAL) \
  31. DEFMAC(PrintHood, CSIDL_PRINTHOOD) \
  32. DEFMAC(Programs, CSIDL_PROGRAMS) \
  33. DEFMAC(Recent, CSIDL_RECENT) \
  34. DEFMAC(SendTo, CSIDL_SENDTO) \
  35. DEFMAC(Start Menu, CSIDL_STARTMENU) \
  36. DEFMAC(StartUp, CSIDL_STARTUP) \
  37. DEFMAC(Templates, CSIDL_TEMPLATES) \
  38. DEFMAC(Common AppData, CSIDL_COMMON_APPDATA) \
  39. DEFMAC(Common Desktop, CSIDL_COMMON_DESKTOPDIRECTORY) \
  40. DEFMAC(Common Personal, CSIDL_COMMON_DOCUMENTS) \
  41. DEFMAC(Common Favorites, CSIDL_COMMON_FAVORITES) \
  42. DEFMAC(Common Programs, CSIDL_COMMON_PROGRAMS) \
  43. DEFMAC(Common Start Menu, CSIDL_COMMON_STARTMENU) \
  44. DEFMAC(Common StartUp, CSIDL_COMMON_STARTUP) \
  45. DEFMAC(Common Templates, CSIDL_COMMON_TEMPLATES) \
  46. enum {
  47. CS_512 = 0,
  48. CS_1024,
  49. CS_2048,
  50. CS_4096,
  51. CS_8192,
  52. CS_16384,
  53. CS_32768,
  54. CS_65536,
  55. CS_131072,
  56. CS_262144,
  57. LAST_CLUSTER_SIZE
  58. };
  59. typedef struct {
  60. PCTSTR RegKey;
  61. UINT Csidl;
  62. PCTSTR Path;
  63. LONG TableOffset;
  64. LONG SpaceNeeded[LAST_CLUSTER_SIZE];
  65. LONG RawSize;
  66. UINT FileCount;
  67. UINT DirectoryCount;
  68. } SFDATA, *PSFDATA;
  69. #define DEFMAC(regName, csidl) {TEXT(#regName),(csidl)},
  70. SFDATA g_Data[] = {SFLIST /*, */ {NULL,0}};
  71. HASHTABLE g_Table;
  72. POOLHANDLE g_Pool;
  73. BOOL g_Verbose = FALSE;
  74. UINT g_ClusterTable[LAST_CLUSTER_SIZE] =
  75. {512,1024,2048,4096,8192,16384,32768,65536,131072,262144};
  76. #define DIRECTORY_SIZE 512
  77. BOOL
  78. pCallEntryPoints (
  79. DWORD Reason
  80. )
  81. {
  82. HINSTANCE Instance;
  83. //
  84. // Simulate DllMain
  85. //
  86. Instance = g_hInst;
  87. //
  88. // Initialize the common libs
  89. //
  90. if (!MigUtil_Entry (Instance, Reason, NULL)) {
  91. return FALSE;
  92. }
  93. /*
  94. if (!MemDb_Entry (Instance, Reason, NULL)) {
  95. return FALSE;
  96. }
  97. */
  98. return TRUE;
  99. }
  100. BOOL
  101. Init (
  102. VOID
  103. )
  104. {
  105. g_hHeap = GetProcessHeap();
  106. g_hInst = GetModuleHandle (NULL);
  107. return pCallEntryPoints (DLL_PROCESS_ATTACH);
  108. }
  109. VOID
  110. Terminate (
  111. VOID
  112. )
  113. {
  114. pCallEntryPoints (DLL_PROCESS_DETACH);
  115. }
  116. BOOL
  117. pInitShellFolderData (
  118. VOID
  119. )
  120. {
  121. PSFDATA sf;
  122. TCHAR buffer[MAX_TCHAR_PATH];
  123. PTSTR p;
  124. sf = g_Data;
  125. while (sf->RegKey) {
  126. if (SHGetFolderPath (NULL, sf->Csidl, NULL, 0, buffer) != S_OK) {
  127. _ftprintf (stderr, TEXT("sfspace: Unable to retrieve folder path for %s.\n"), sf->RegKey);
  128. return FALSE;
  129. }
  130. sf->Path = PoolMemDuplicateString (g_Pool, buffer);
  131. //
  132. // We don't have a CSIDL for the local settings directory. We need to hack it.
  133. //
  134. if (StringIMatch (sf->RegKey, TEXT("Local Settings"))) {
  135. p = _tcsrchr (sf->Path, TEXT('\\'));
  136. MYASSERT (p);
  137. *p = 0;
  138. if (g_Verbose) {
  139. _tprintf (TEXT("sfspace: Hacked path of local settings to %s.\n"), sf->Path);
  140. }
  141. }
  142. sf->TableOffset = HtAddString (g_Table, sf->Path);
  143. if (g_Verbose) {
  144. _tprintf (TEXT("sfspace: Shell folder %s has path %s.\n"), sf->RegKey, sf->Path);
  145. }
  146. sf++;
  147. }
  148. return TRUE;
  149. }
  150. BOOL
  151. pGatherSpaceRequirements (
  152. VOID
  153. )
  154. {
  155. PSFDATA sf;
  156. UINT i;
  157. TREE_ENUM e;
  158. LONG offset;
  159. sf = g_Data;
  160. while (sf->RegKey) {
  161. if (EnumFirstFileInTree (&e, sf->Path, NULL, FALSE)) {
  162. do {
  163. if (e.Directory) {
  164. //
  165. // Check to see if this is a different shell folder.
  166. //
  167. offset = HtFindString (g_Table, e.FullPath);
  168. if (offset && offset != sf->TableOffset) {
  169. //
  170. // This is actually another shell folder. Don't enumerate
  171. // it.
  172. //
  173. if (g_Verbose) {
  174. _tprintf (TEXT("sfspace: %s is handled by another shell folder.\n"), e.FullPath);
  175. }
  176. AbortEnumCurrentDir (&e);
  177. }
  178. else {
  179. //
  180. // Increment directory count for this shell folder.
  181. //
  182. sf->DirectoryCount++;
  183. }
  184. }
  185. else {
  186. //
  187. // this is a file. Add its data to our structure.
  188. //
  189. sf->FileCount++;
  190. sf->RawSize += e.FindData->nFileSizeLow;
  191. for (i=0; i<LAST_CLUSTER_SIZE; i++) {
  192. //
  193. // We assume NT doesn't install any massively large files by default.
  194. //
  195. MYASSERT (!e.FindData->nFileSizeHigh);
  196. sf->SpaceNeeded[i] += ((e.FindData->nFileSizeLow / g_ClusterTable[i]) * g_ClusterTable[i]) + g_ClusterTable[i];
  197. }
  198. }
  199. } while (EnumNextFileInTree (&e));
  200. }
  201. //
  202. // Add the space for all of the directories we found in this shell folder.
  203. //
  204. for (i=0; i<LAST_CLUSTER_SIZE; i++) {
  205. sf->SpaceNeeded[i] += (((sf->DirectoryCount * DIRECTORY_SIZE) / g_ClusterTable[i]) * g_ClusterTable[i]) + g_ClusterTable[i];
  206. }
  207. if (g_Verbose) {
  208. _tprintf (
  209. TEXT("sfspace: %u files and %u directories enumerated for shell folder %s. Space needed (512k cluster size): %u Raw Space: %u\n"),
  210. sf->FileCount,
  211. sf->DirectoryCount,
  212. sf->RegKey,
  213. sf->SpaceNeeded[CS_512],
  214. sf->RawSize
  215. );
  216. }
  217. sf++;
  218. }
  219. return TRUE;
  220. }
  221. PCTSTR
  222. pLeftJustify (
  223. IN PCTSTR String,
  224. IN UINT FieldWidth
  225. )
  226. {
  227. static TCHAR rBuffer[MAX_TCHAR_PATH];
  228. UINT length;
  229. UINT i;
  230. MYASSERT(String);
  231. length = CharCount (String);
  232. MYASSERT(FieldWidth < MAX_TCHAR_PATH && length < FieldWidth);
  233. StringCopy (rBuffer,String);
  234. for (i=length; i<FieldWidth; i++) {
  235. rBuffer[i] = TEXT(' ');
  236. }
  237. rBuffer[i] = 0;
  238. return rBuffer;
  239. }
  240. VOID
  241. pOutputSpaceTable (
  242. VOID
  243. )
  244. {
  245. PSFDATA sf;
  246. UINT i;
  247. TCHAR buffer[20];
  248. _tprintf (TEXT("[%s]\n"), S_SHELL_FOLDERS_DISK_SPACE);
  249. _tprintf (
  250. TEXT("@*: \n")
  251. TEXT("@*: Disk space requirements for each shell folder. The key name is a registry \n")
  252. TEXT("@*: value name. \n")
  253. TEXT("@*: \n")
  254. );
  255. sf = g_Data;
  256. while (sf->RegKey) {
  257. _tprintf (TEXT("%s"),pLeftJustify (sf->RegKey,20));
  258. for (i=0; i<LAST_CLUSTER_SIZE; i++) {
  259. _tprintf (TEXT("%s %u"),i ? TEXT(",") : TEXT("="), sf->SpaceNeeded[i]);
  260. }
  261. _tprintf (TEXT("\n"));
  262. sf++;
  263. }
  264. }
  265. VOID
  266. HelpAndExit (
  267. VOID
  268. )
  269. {
  270. //
  271. // This routine is called whenever command line args are wrong
  272. //
  273. _ftprintf (
  274. stderr,
  275. TEXT("Command Line Syntax:\n\n")
  276. TEXT(" sfspace [/V]\n")
  277. TEXT("\nDescription:\n\n")
  278. TEXT(" sfspace gathers the space requirements for the default\n")
  279. TEXT(" shell folders installed by Windows 2000. It should be\n")
  280. TEXT(" run against a clean install of Windows 2000.\n")
  281. TEXT("\nArguments:\n\n")
  282. TEXT(" /V Instructs sfspace to generate verbose output.\n")
  283. );
  284. exit (1);
  285. }
  286. INT
  287. __cdecl
  288. _tmain (
  289. INT argc,
  290. PCTSTR argv[]
  291. )
  292. {
  293. INT i;
  294. for (i = 1 ; i < argc ; i++) {
  295. if (argv[i][0] == TEXT('/') || argv[i][0] == TEXT('-')) {
  296. switch (_totlower (_tcsnextc (&argv[i][1]))) {
  297. case TEXT('v'):
  298. //
  299. // Verbose output wanted.
  300. //
  301. g_Verbose = TRUE;
  302. break;
  303. default:
  304. HelpAndExit();
  305. }
  306. } else {
  307. //
  308. // Parse other args that don't require / or -
  309. //
  310. //
  311. // None
  312. //
  313. HelpAndExit();
  314. }
  315. }
  316. //
  317. // Begin processing
  318. //
  319. if (!Init()) {
  320. return 0;
  321. }
  322. //
  323. // Initialize data structures.
  324. //
  325. g_Table = HtAlloc ();
  326. g_Pool = PoolMemInitPool ();
  327. _try {
  328. if (!pInitShellFolderData ()) {
  329. _ftprintf (stderr, TEXT("sfspace: Unable to initialize shell folder data. Exiting.\n"));
  330. __leave;
  331. }
  332. if (!pGatherSpaceRequirements ()) {
  333. _ftprintf (stderr, TEXT("sfspace: Unable to gather space requirements for shell folders. Exiting.\n"));
  334. __leave;
  335. }
  336. pOutputSpaceTable ();
  337. }
  338. __finally {
  339. HtFree (g_Table);
  340. PoolMemDestroyPool (g_Pool);
  341. }
  342. //
  343. // End of processing
  344. //
  345. Terminate();
  346. return 0;
  347. }