Source code of Windows XP (NT5)
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.

531 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. progress.c
  5. Abstract:
  6. This file implements routines that estimate the size of the progress
  7. bar.
  8. Author:
  9. Jim Schmidt (jimschm) 02-Jul-1998
  10. Revision History:
  11. jimschm 23-Sep-1998 MigrateShellFolders & split of usermig.c
  12. --*/
  13. /*++
  14. Macro Expansion List Description:
  15. The macro expansion lists FIRST_SYSTEM_ROUTINES, USER_ROUTINES and
  16. LAST_SYSTEM_ROUTINES list all the functions called to perform the migration
  17. of user and system settings. The functions are executed in the order they
  18. appear. Each function is responsible for estimating a tick count and ticking
  19. the progress bar.
  20. Line Syntax:
  21. SYSFUNCTION(Function, Flag) (for FIRST_SYSTEM_ROUTINES and LAST_SYSTEM_ROUTINES)
  22. or
  23. USERFUNCTION(Function, Flag) (for USER_ROUTINES)
  24. Arguments:
  25. Function - These functions must return DWORD and are called with a request as a parameter,
  26. request that can be either REQUEST_QUERYTICKS (the function should estimate the
  27. number of ticks it needs) or REQUEST_RUN (the function should do it's job).
  28. For user functions there are also three more parameters (UserName, UserAccount,
  29. and a handle to HKCU)
  30. Flag - Specifies NOFAIL if the function terminates migration when it fails, or
  31. CANFAIL if migration can proceed even if the function fails
  32. Variables Generated From List:
  33. g_MigrationFnList
  34. For accessing the arrays there are the following functions:
  35. PrepareMigrationProgressBar
  36. PerformMigration
  37. --*/
  38. #include "pch.h"
  39. #define NOFAIL FALSE
  40. #define CANFAIL TRUE
  41. #define FIRST_SYSTEM_ROUTINES \
  42. SYSFUNCTION(PrepareEnvironment, NOFAIL) \
  43. SYSFUNCTION(ResolveDomains, NOFAIL) \
  44. SYSFUNCTION(DeleteSysTapiSettings, NOFAIL) \
  45. SYSFUNCTION(ProcessLocalMachine_First, CANFAIL) \
  46. SYSFUNCTION(UninstallStartMenuCleanupPreparation, CANFAIL) \
  47. SYSFUNCTION(RemoveBootIniCancelOption, CANFAIL) \
  48. SYSFUNCTION(MigrateShellFolders, CANFAIL) \
  49. SYSFUNCTION(MigrateGhostSystemFiles, CANFAIL) \
  50. #define USER_ROUTINES \
  51. USERFUNCTION(RunPerUserUninstallUserProfileCleanupPreparation, CANFAIL) \
  52. USERFUNCTION(PrepareUserForMigration, NOFAIL) \
  53. USERFUNCTION(DeleteUserTapiSettings, NOFAIL) \
  54. USERFUNCTION(MigrateUserRegistry, CANFAIL) \
  55. USERFUNCTION(MigrateLogonPromptSettings, CANFAIL) \
  56. USERFUNCTION(MigrateUserSettings, CANFAIL) \
  57. USERFUNCTION(RunPerUserExternalProcesses, CANFAIL) \
  58. USERFUNCTION(SaveMigratedUserHive, CANFAIL) \
  59. #define LAST_SYSTEM_ROUTINES \
  60. SYSFUNCTION(DoCopyFile, CANFAIL) \
  61. SYSFUNCTION(ProcessLocalMachine_Last, CANFAIL) \
  62. SYSFUNCTION(ConvertHiveFiles, CANFAIL) \
  63. SYSFUNCTION(MigrateBriefcases, CANFAIL) \
  64. SYSFUNCTION(MigrateAtmFonts, CANFAIL) \
  65. SYSFUNCTION(AddOptionsDiskCleaner, CANFAIL) \
  66. SYSFUNCTION(DoFileEdit, CANFAIL) \
  67. SYSFUNCTION(RunSystemExternalProcesses, CANFAIL) \
  68. SYSFUNCTION(ProcessMigrationDLLs, CANFAIL) \
  69. SYSFUNCTION(DisableFiles, CANFAIL) \
  70. SYSFUNCTION(RunSystemUninstallUserProfileCleanupPreparation, CANFAIL) \
  71. SYSFUNCTION(WriteBackupInfo, CANFAIL) \
  72. //
  73. // Declare tables of processing structures
  74. //
  75. // Create a combined list
  76. #define MIGRATION_ROUTINES FIRST_SYSTEM_ROUTINES USER_ROUTINES LAST_SYSTEM_ROUTINES
  77. // Processing functions types
  78. typedef DWORD (MIGMAIN_SYS_PROTOTYPE) (DWORD Request);
  79. typedef MIGMAIN_SYS_PROTOTYPE * MIGMAIN_SYS_FN;
  80. typedef DWORD (MIGMAIN_USER_PROTOTYPE) (DWORD Request, PMIGRATE_USER_ENUM EnumPtr);
  81. typedef MIGMAIN_USER_PROTOTYPE * MIGMAIN_USER_FN;
  82. // Structure holding state for processing functions
  83. typedef struct {
  84. // One of the two will be NULL, the other will be a valid fn ptr:
  85. MIGMAIN_SYS_FN SysFnPtr;
  86. MIGMAIN_USER_FN UserFnPtr;
  87. BOOL CanFail;
  88. UINT Ticks;
  89. PCTSTR FnName;
  90. GROWBUFFER SliceIdArray;
  91. } PROCESSING_ROUTINE, *PPROCESSING_ROUTINE;
  92. #define PROCESSING_ROUTINE_TERMINATOR {NULL, NULL, FALSE, 0, NULL, GROWBUF_INIT}
  93. // Declaration of prototypes
  94. #define SYSFUNCTION(fn,flag) MIGMAIN_SYS_PROTOTYPE fn;
  95. #define USERFUNCTION(fn,flag) MIGMAIN_USER_PROTOTYPE fn;
  96. MIGRATION_ROUTINES
  97. #undef SYSFUNCTION
  98. #undef USERFUNCTION
  99. // Declaration of table
  100. #define SYSFUNCTION(fn,flag) {fn, NULL, flag, 0, L###fn, GROWBUF_INIT},
  101. #define USERFUNCTION(fn,flag) {NULL, fn, flag, 0, L###fn, GROWBUF_INIT},
  102. static PROCESSING_ROUTINE g_FirstSystemRoutines[] = {
  103. FIRST_SYSTEM_ROUTINES /* , */
  104. PROCESSING_ROUTINE_TERMINATOR
  105. };
  106. static PROCESSING_ROUTINE g_UserRoutines [] = {
  107. USER_ROUTINES /* , */
  108. PROCESSING_ROUTINE_TERMINATOR
  109. };
  110. static PROCESSING_ROUTINE g_LastSystemRoutines[] = {
  111. LAST_SYSTEM_ROUTINES /* , */
  112. PROCESSING_ROUTINE_TERMINATOR
  113. };
  114. #undef SYSFUNCTION
  115. #undef USERFUNCTION
  116. //
  117. // Prototypes
  118. //
  119. BOOL
  120. pProcessTable (
  121. IN DWORD Request,
  122. IN PPROCESSING_ROUTINE Table
  123. );
  124. //
  125. // Implementation
  126. //
  127. VOID
  128. pInitTable (
  129. PPROCESSING_ROUTINE p
  130. )
  131. {
  132. while (p->SysFnPtr || p->UserFnPtr) {
  133. p->SliceIdArray.GrowSize = sizeof (DWORD) * 8;
  134. p++;
  135. }
  136. }
  137. VOID
  138. InitProcessingTable (
  139. VOID
  140. )
  141. {
  142. pInitTable (g_FirstSystemRoutines);
  143. pInitTable (g_UserRoutines);
  144. pInitTable (g_LastSystemRoutines);
  145. }
  146. VOID
  147. pTerminateTable (
  148. PPROCESSING_ROUTINE p
  149. )
  150. {
  151. while (p->SysFnPtr || p->UserFnPtr) {
  152. FreeGrowBuffer (&p->SliceIdArray);
  153. p++;
  154. }
  155. }
  156. VOID
  157. TerminateProcessingTable (
  158. VOID
  159. )
  160. {
  161. pTerminateTable (g_FirstSystemRoutines);
  162. pTerminateTable (g_UserRoutines);
  163. pTerminateTable (g_LastSystemRoutines);
  164. }
  165. BOOL
  166. pCallAllRoutines (
  167. BOOL Run
  168. )
  169. {
  170. BOOL b;
  171. DWORD Request;
  172. Request = Run ? REQUEST_RUN : REQUEST_QUERYTICKS;
  173. b = pProcessTable (Request, g_FirstSystemRoutines);
  174. if (b && Run) {
  175. b = pProcessTable (REQUEST_BEGINUSERPROCESSING, g_UserRoutines);
  176. }
  177. if (b) {
  178. b = pProcessTable (Request, g_UserRoutines);
  179. }
  180. if (b && Run) {
  181. b = pProcessTable (REQUEST_ENDUSERPROCESSING, g_UserRoutines);
  182. }
  183. if (b) {
  184. b = pProcessTable (Request, g_LastSystemRoutines);
  185. }
  186. return b;
  187. }
  188. VOID
  189. PrepareMigrationProgressBar (
  190. VOID
  191. )
  192. {
  193. InitProcessingTable();
  194. pCallAllRoutines (FALSE);
  195. }
  196. BOOL
  197. CallAllMigrationFunctions (
  198. VOID
  199. )
  200. {
  201. return pCallAllRoutines (TRUE);
  202. }
  203. BOOL
  204. pProcessWorker (
  205. IN DWORD Request,
  206. IN PPROCESSING_ROUTINE fn,
  207. IN PMIGRATE_USER_ENUM EnumPtr OPTIONAL
  208. )
  209. {
  210. DWORD rc;
  211. PDWORD SliceId;
  212. DWORD Size;
  213. BOOL Result = TRUE;
  214. //
  215. // If running the function, start the progress bar slice
  216. //
  217. if (Request == REQUEST_RUN) {
  218. if (fn->Ticks == 0) {
  219. return TRUE;
  220. }
  221. Size = fn->SliceIdArray.End / sizeof (DWORD);
  222. if (fn->SliceIdArray.UserIndex >= Size) {
  223. DEBUGMSG ((DBG_WHOOPS, "pProcessWorker: QUERYTICKS vs. RUN mismatch"));
  224. return fn->CanFail;
  225. }
  226. SliceId = (PDWORD) fn->SliceIdArray.Buf + fn->SliceIdArray.UserIndex;
  227. fn->SliceIdArray.UserIndex += 1;
  228. BeginSliceProcessing (*SliceId);
  229. DEBUGLOGTIME (("Starting function: %ls", fn->FnName));
  230. }
  231. //
  232. // Now call the function
  233. //
  234. if (fn->SysFnPtr) {
  235. //
  236. // System processing
  237. //
  238. MYASSERT (!EnumPtr);
  239. rc = fn->SysFnPtr (Request);
  240. if (Request != REQUEST_QUERYTICKS && rc != ERROR_SUCCESS) {
  241. DEBUGMSG ((DBG_ERROR, "%s failed with rc=%u", fn->FnName, rc));
  242. Result = fn->CanFail;
  243. }
  244. } else {
  245. //
  246. // User processing
  247. //
  248. MYASSERT (fn->UserFnPtr);
  249. rc = fn->UserFnPtr (Request, EnumPtr);
  250. if (Request != REQUEST_QUERYTICKS && rc != ERROR_SUCCESS) {
  251. DEBUGMSG ((DBG_ERROR, "%s failed with rc=%u", fn->FnName, rc));
  252. Result = fn->CanFail;
  253. }
  254. }
  255. //
  256. // If running the function, end the progress bar slice
  257. //
  258. if (Request == REQUEST_RUN) {
  259. if (rc != ERROR_SUCCESS) {
  260. LOG ((LOG_ERROR, "Failure in %s, rc=%u", fn->FnName, rc));
  261. }
  262. EndSliceProcessing();
  263. DEBUGLOGTIME (("Function complete: %ls", fn->FnName));
  264. }
  265. if (Request != REQUEST_QUERYTICKS) {
  266. SetLastError (rc);
  267. }
  268. //
  269. // If querying the ticks, register them and add slice ID to grow buffer
  270. //
  271. else {
  272. fn->Ticks += rc;
  273. SliceId = (PDWORD) GrowBuffer (&fn->SliceIdArray, sizeof (DWORD));
  274. *SliceId = RegisterProgressBarSlice (rc);
  275. }
  276. return Result;
  277. }
  278. BOOL
  279. pProcessTable (
  280. IN DWORD Request,
  281. IN PPROCESSING_ROUTINE Table
  282. )
  283. /*++
  284. Routine Description:
  285. pProcessTable calls all routines in the specified table to perform
  286. the specified request.
  287. Arguments:
  288. Request - Specifies REQUEST_QUERYTICKS when a tick estimate is needed,
  289. or REQUEST_RUN when the function needs to perform its
  290. processing. For User routines, there are the additional two
  291. requests REQUEST_BEGINUSERPROCESSING and REQUEST_ENDUSERPROCESSING
  292. Functions can use these requests to init/free needed resources
  293. for user processing.
  294. Return Value:
  295. none
  296. --*/
  297. {
  298. MIGRATE_USER_ENUM e;
  299. PPROCESSING_ROUTINE OrgStart;
  300. DWORD Flags;
  301. g_DomainUserName = NULL;
  302. g_Win9xUserName = NULL;
  303. g_FixedUserName = NULL;
  304. MYASSERT (Table->SysFnPtr || Table->UserFnPtr);
  305. while (Table->SysFnPtr || Table->UserFnPtr) {
  306. if (Table->SysFnPtr ||
  307. Request == REQUEST_BEGINUSERPROCESSING ||
  308. Request == REQUEST_ENDUSERPROCESSING
  309. ) {
  310. //
  311. // Call system routine, or call per-user routine with begin or
  312. // end request
  313. //
  314. __try {
  315. if (!pProcessWorker (Request, Table, NULL)) {
  316. return FALSE;
  317. }
  318. } __except (1) {
  319. LOG ((LOG_WARNING, "Unhandled exception occurred during processing of function %s.", Table->FnName));
  320. SafeModeExceptionOccured ();
  321. if (!Table->CanFail) {
  322. return FALSE;
  323. }
  324. }
  325. //
  326. // Loop inc
  327. //
  328. Table++;
  329. } else {
  330. //
  331. // Enumerate each user, and run through all the per-user
  332. // routines in the group.
  333. //
  334. OrgStart = Table;
  335. if (Request == REQUEST_QUERYTICKS) {
  336. Flags = ENUM_NO_FLAGS;
  337. } else {
  338. Flags = ENUM_SET_WIN9X_HKR;
  339. }
  340. if (EnumFirstUserToMigrate (&e, Flags)) {
  341. do {
  342. if (!e.CreateOnly) {
  343. for (Table = OrgStart ; Table->UserFnPtr ; Table++) {
  344. __try {
  345. if (!pProcessWorker (Request, Table, &e)) {
  346. return FALSE;
  347. }
  348. } __except (1) {
  349. LOG ((LOG_WARNING, "Unhandled exception occurred during processing of function %s.", Table->FnName));
  350. SafeModeExceptionOccured ();
  351. if (!Table->CanFail) {
  352. return FALSE;
  353. }
  354. }
  355. }
  356. }
  357. } while (EnumNextUserToMigrate (&e));
  358. }
  359. ELSE_DEBUGMSG ((DBG_WARNING, "No active users to process!"));
  360. //
  361. // Loop inc
  362. //
  363. while (Table->UserFnPtr) {
  364. Table++;
  365. }
  366. }
  367. TickProgressBar ();
  368. }
  369. return TRUE;
  370. }