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.

2043 lines
52 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dosmig95.c
  5. Abstract:
  6. Handles win95 side gathering of data from config.sys and autoexec.bat files.
  7. Author:
  8. Marc R. Whitten (marcw) 15-Feb-1997
  9. Revision History:
  10. Marc R. Whitten (marcw) 08-Mar-1999 - Cleanup Environment variable parsing.
  11. Marc R. Whitten (marcw) 5-Sep-1997 - Major changes.
  12. Marc R. Whitten (marcw) 18-Aug-1997 - Bug sweep.
  13. Marc R. Whitten (marcw) 14-Apr-1997 - Dosmig is now ProgressBar aware.
  14. --*/
  15. #include "pch.h"
  16. #define DBG_DOSMIG "DOSMIG"
  17. typedef BOOL (RULEFUNC)(PLINESTRUCT,DWORD);
  18. typedef struct _PARSERULE PARSERULE, *PPARSERULE;
  19. struct _PARSERULE {
  20. PCTSTR Name;
  21. PCTSTR Pattern;
  22. RULEFUNC * Handle;
  23. DWORD Parameter;
  24. PPARSERULE Next;
  25. };
  26. typedef enum {
  27. DOSMIG_UNUSED,
  28. DOSMIG_BAD,
  29. DOSMIG_UNKNOWN,
  30. DOSMIG_USE,
  31. DOSMIG_MIGRATE,
  32. DOSMIG_IGNORE,
  33. DOSMIG_LAST
  34. } DOSMIG_LINETAG, *PDOSMIG_LINETAG;
  35. typedef struct _PARSERULES {
  36. PCTSTR Name;
  37. PPARSERULE RuleList;
  38. PPARSERULE DefaultRule;
  39. } PARSERULES, *PPARSERULES;
  40. BOOL g_IncompatibilityDetected = FALSE;
  41. GROWBUFFER g_IncompatibilityBuffer = GROWBUF_INIT;
  42. //
  43. // Global pointers to the rule lists for config.sys and batch files.
  44. //
  45. PARSERULES g_ConfigSysRules;
  46. PARSERULES g_BatchFileRules;
  47. PPARSERULES g_CurrentRules = NULL;
  48. //
  49. // This variable holds the offset within memdb to where the file currently being parsed is saved.
  50. //
  51. DWORD g_CurrentFileOffset;
  52. //
  53. // This growlist holds the list of all files that will be parsed. It can increase during parsing
  54. // (e.g. by encountering a CALL statement in a batch file.)
  55. //
  56. GROWLIST g_FileList = GROWLIST_INIT;
  57. GROWBUFFER g_LineGrowBuf = GROWBUF_INIT;
  58. GROWBUFFER g_ExtraPaths = GROWBUF_INIT;
  59. #define MAXFILESIZE 0xFFFFFFFF
  60. //
  61. // Various bits of state that are kept during parsing..
  62. //
  63. PCTSTR g_CurrentFile;
  64. PCTSTR g_CurrentLine;
  65. DWORD g_CurrentLineNumber;
  66. POOLHANDLE g_DosMigPool = NULL;
  67. #define BATCHFILELIST \
  68. DEFAULTPARSERULE(TEXT("Default Rule"),NULL,pHandleUnknownBatLine,0) \
  69. PARSERULE(TEXT("Rem"),TEXT("REM *"),pSaveItem,DOSMIG_USE) \
  70. PARSERULE(TEXT(" "),TEXT("*DOSKEY*"),pSaveItem,DOSMIG_MIGRATE) \
  71. PARSERULE(TEXT(": (Menu or Label"),TEXT(":*"),pSaveItem,DOSMIG_USE) \
  72. PARSERULE(TEXT("@"),TEXT("@*"),pHandleAtSign,0) \
  73. PARSERULE(TEXT("CLS"),TEXT("CLS *"),pSaveItem,DOSMIG_USE) \
  74. PARSERULE(TEXT("CD"),TEXT("CD *"),pSaveItem,DOSMIG_USE) \
  75. PARSERULE(TEXT("CHDIR"),TEXT("CHDIR *"),pSaveItem,DOSMIG_USE) \
  76. PARSERULE(TEXT("PAUSE"),TEXT("PAUSE *"),pSaveItem,DOSMIG_USE) \
  77. PARSERULE(TEXT("ECHO"),TEXT("ECHO *"),pSaveItem,DOSMIG_USE) \
  78. PARSERULE(TEXT("ATTRIB"),TEXT("ATTRIB *"),pSaveItem,DOSMIG_USE) \
  79. PARSERULE(TEXT("CHDIR"),TEXT("CHDIR *"),pSaveItem,DOSMIG_USE) \
  80. PARSERULE(TEXT("CHCP"),TEXT("CHCP *"),pSaveItem,DOSMIG_USE) \
  81. PARSERULE(TEXT("CHOICE"),TEXT("CHOICE *"),pSaveItem,DOSMIG_IGNORE) \
  82. PARSERULE(TEXT("CALL"),TEXT("CALL *"),pHandleCall,0) \
  83. PARSERULE(TEXT("COMMAND"),TEXT("COMMAND *"),pSaveItem,DOSMIG_MIGRATE) \
  84. PARSERULE(TEXT("CHKDSK"),TEXT("CHKDSK *"),pSaveItem,DOSMIG_IGNORE) \
  85. PARSERULE(TEXT("COPY"),TEXT("COPY *"),pSaveItem,DOSMIG_USE) \
  86. PARSERULE(TEXT("CTTY"),TEXT("CTTY *"),pSaveItem,DOSMIG_IGNORE) \
  87. PARSERULE(TEXT("DATE"),TEXT("DATE *"),pSaveItem,DOSMIG_USE) \
  88. PARSERULE(TEXT("DBLSPACE"),TEXT("DBLSPACE *"),pSaveItem,DOSMIG_BAD) \
  89. PARSERULE(TEXT("DEFRAG"),TEXT("DEFRAG *"),pSaveItem,DOSMIG_IGNORE) \
  90. PARSERULE(TEXT("DEL"),TEXT("DEL *"),pSaveItem,DOSMIG_BAD) \
  91. PARSERULE(TEXT("DELETE"),TEXT("DELETE *"),pSaveItem,DOSMIG_USE) \
  92. PARSERULE(TEXT("DELOLDDOS"),TEXT("DELOLDDOS *"),pSaveItem,DOSMIG_IGNORE) \
  93. PARSERULE(TEXT("DELTREE"),TEXT("DELTREE *"),pSaveItem,DOSMIG_BAD) \
  94. PARSERULE(TEXT("DIR"),TEXT("DIR *"),pSaveItem,DOSMIG_USE) \
  95. PARSERULE(TEXT("DISKCOMP"),TEXT("DISKCOMP *"),pSaveItem,DOSMIG_USE) \
  96. PARSERULE(TEXT("DISKCOPY"),TEXT("DISKCOPY *"),pSaveItem,DOSMIG_USE) \
  97. PARSERULE(TEXT("DOSSHELL"),TEXT("DOSSHELL *"),pSaveItem,DOSMIG_BAD) \
  98. PARSERULE(TEXT("DRVSPACE"),TEXT("DRVSPACE *"),pSaveItem,DOSMIG_BAD) \
  99. PARSERULE(TEXT("ECHO"),TEXT("ECHO *"),pSaveItem,DOSMIG_USE) \
  100. PARSERULE(TEXT("EDIT"),TEXT("EDIT *"),pSaveItem,DOSMIG_USE) \
  101. PARSERULE(TEXT("EMM386"),TEXT("EMM386 *"),pSaveItem,DOSMIG_IGNORE) \
  102. PARSERULE(TEXT("ERASE"),TEXT("ERASE *"),pSaveItem,DOSMIG_USE) \
  103. PARSERULE(TEXT("EXIT"),TEXT("EXIT *"),pSaveItem,DOSMIG_USE) \
  104. PARSERULE(TEXT("EXPAND"),TEXT("EXPAND *"),pSaveItem,DOSMIG_USE) \
  105. PARSERULE(TEXT("FASTHELP"),TEXT("FASTHELP *"),pSaveItem,DOSMIG_IGNORE) \
  106. PARSERULE(TEXT("FASTOPEN"),TEXT("FASTOPEN *"),pSaveItem,DOSMIG_IGNORE) \
  107. PARSERULE(TEXT("FC"),TEXT("FC *"),pSaveItem,DOSMIG_USE) \
  108. PARSERULE(TEXT("FDISK"),TEXT("FDISK *"),pSaveItem,DOSMIG_BAD) \
  109. PARSERULE(TEXT("FIND"),TEXT("FIND *"),pSaveItem,DOSMIG_USE) \
  110. PARSERULE(TEXT("FOR"),TEXT("FOR *"),pSaveItem,DOSMIG_USE) \
  111. PARSERULE(TEXT("FORMAT"),TEXT("FORMAT *"),pSaveItem,DOSMIG_USE) \
  112. PARSERULE(TEXT("GOTO"),TEXT("GOTO *"),pSaveItem,DOSMIG_USE) \
  113. PARSERULE(TEXT("GRAPHICS"),TEXT("GRAPHICS *"),pSaveItem,DOSMIG_USE) \
  114. PARSERULE(TEXT("HELP"),TEXT("HELP *"),pSaveItem,DOSMIG_USE) \
  115. PARSERULE(TEXT("IF"),TEXT("IF *"),pSaveItem,DOSMIG_USE) \
  116. PARSERULE(TEXT("INTERLNK"),TEXT("INTERLNK*"),pSaveItem,DOSMIG_BAD) \
  117. PARSERULE(TEXT("INTERSVR"),TEXT("INTERSVR*"),pSaveItem,DOSMIG_BAD) \
  118. PARSERULE(TEXT("KEYB"),TEXT("KEYB *"),pSaveItem,DOSMIG_USE) \
  119. PARSERULE(TEXT("LABEL"),TEXT("LABEL *"),pSaveItem,DOSMIG_USE) \
  120. PARSERULE(TEXT("LH"),TEXT("LH *"),pHandleLoadHigh,0) \
  121. PARSERULE(TEXT("LOADHIGH"),TEXT("LOADHIGH *"),pHandleLoadHigh,0) \
  122. PARSERULE(TEXT("MD"),TEXT("MD *"),pSaveItem,DOSMIG_USE) \
  123. PARSERULE(TEXT("MKDIR"),TEXT("MKDIR *"),pSaveItem,DOSMIG_USE) \
  124. PARSERULE(TEXT("MEM"),TEXT("MEM *"),pSaveItem,DOSMIG_USE) \
  125. PARSERULE(TEXT("MEMMAKER"),TEXT("MEMMAKER *"),pSaveItem,DOSMIG_BAD) \
  126. PARSERULE(TEXT("MODE"),TEXT("MODE *"),pSaveItem,DOSMIG_USE) \
  127. PARSERULE(TEXT("MORE"),TEXT("MORE *"),pSaveItem,DOSMIG_USE) \
  128. PARSERULE(TEXT("MOVE"),TEXT("MOVE *"),pSaveItem,DOSMIG_USE) \
  129. PARSERULE(TEXT("MSAV"),TEXT("MSAV *"),pSaveItem,DOSMIG_BAD) \
  130. PARSERULE(TEXT("MSBACKUP"),TEXT("MSBACKUP *"),pSaveItem,DOSMIG_BAD) \
  131. PARSERULE(TEXT("MSCDEX"),TEXT("*MSCDEX*"),pHandleMSCDEX,0) \
  132. PARSERULE(TEXT("MSD"),TEXT("MSD *"),pSaveItem,DOSMIG_IGNORE) \
  133. PARSERULE(TEXT("NLSFUNC"),TEXT("NLSFUNC *"),pSaveItem,DOSMIG_IGNORE) \
  134. PARSERULE(TEXT("NUMLOCK"),TEXT("NUMLOCK *"),pSaveItem,DOSMIG_IGNORE) \
  135. PARSERULE(TEXT("PATH"),TEXT("PATH *"),pSaveItem,DOSMIG_MIGRATE) \
  136. PARSERULE(TEXT("PATH"),TEXT("PATH*=*"),pSaveItem,DOSMIG_MIGRATE) \
  137. PARSERULE(TEXT("PAUSE"),TEXT("PAUSE *"),pSaveItem,DOSMIG_USE) \
  138. PARSERULE(TEXT("POWER"),TEXT("POWER *"),pSaveItem,DOSMIG_IGNORE) \
  139. PARSERULE(TEXT("PRINT"),TEXT("PRINT *"),pSaveItem,DOSMIG_USE) \
  140. PARSERULE(TEXT("PROMPT"),TEXT("PROMPT*"),pSaveItem,DOSMIG_MIGRATE) \
  141. PARSERULE(TEXT("QBASIC"),TEXT("QBASIC *"),pSaveItem,DOSMIG_USE) \
  142. PARSERULE(TEXT("RD"),TEXT("RD *"),pSaveItem,DOSMIG_USE) \
  143. PARSERULE(TEXT("RMDIR"),TEXT("RMDIR *"),pSaveItem,DOSMIG_USE) \
  144. PARSERULE(TEXT("REN"),TEXT("REN *"),pSaveItem,DOSMIG_USE) \
  145. PARSERULE(TEXT("RENAME"),TEXT("RENAME *"),pSaveItem,DOSMIG_USE) \
  146. PARSERULE(TEXT("REPLACE"),TEXT("REPLACE *"),pSaveItem,DOSMIG_USE) \
  147. PARSERULE(TEXT("RESTORE"),TEXT("RESTORE *"),pSaveItem,DOSMIG_USE) \
  148. PARSERULE(TEXT("SCANDISK"),TEXT("SCANDISK *"),pSaveItem,DOSMIG_BAD) \
  149. PARSERULE(TEXT("SET"),TEXT("SET*=*"),pSaveItem,DOSMIG_MIGRATE) \
  150. PARSERULE(TEXT("SET"),TEXT("SET *"),pSaveItem,DOSMIG_MIGRATE) \
  151. PARSERULE(TEXT("SETVER"),TEXT("SETVER *"),pSaveItem,DOSMIG_USE) \
  152. PARSERULE(TEXT("SHARE"),TEXT("SHARE *"),pSaveItem,DOSMIG_USE) \
  153. PARSERULE(TEXT("SHIFT"),TEXT("SHIFT *"),pSaveItem,DOSMIG_USE) \
  154. PARSERULE(TEXT("SMARTDRV"),TEXT("SMARTDRV*"),pSaveItem,DOSMIG_IGNORE) \
  155. PARSERULE(TEXT("SORT"),TEXT("SORT *"),pSaveItem,DOSMIG_USE) \
  156. PARSERULE(TEXT("SUBST"),TEXT("SUBST *"),pSaveItem,DOSMIG_USE) \
  157. PARSERULE(TEXT("SYS"),TEXT("SYS *"),pSaveItem,DOSMIG_BAD) \
  158. PARSERULE(TEXT("TIME"),TEXT("TIME *"),pSaveItem,DOSMIG_USE) \
  159. PARSERULE(TEXT("TREE"),TEXT("TREE *"),pSaveItem,DOSMIG_USE) \
  160. PARSERULE(TEXT("TRUENAME"),TEXT("TRUENAME *"),pSaveItem,DOSMIG_BAD) \
  161. PARSERULE(TEXT("TYPE"),TEXT("TYPE *"),pSaveItem,DOSMIG_USE) \
  162. PARSERULE(TEXT("UNDELETE"),TEXT("UNDELETE *"),pSaveItem,DOSMIG_BAD) \
  163. PARSERULE(TEXT("UNFORMAT"),TEXT("UNFORMAT *"),pSaveItem,DOSMIG_BAD) \
  164. PARSERULE(TEXT("VER"),TEXT("VER *"),pSaveItem,DOSMIG_USE) \
  165. PARSERULE(TEXT("VERIFY"),TEXT("VERIFY *"),pSaveItem,DOSMIG_USE) \
  166. PARSERULE(TEXT("VOL"),TEXT("VOL *"),pSaveItem,DOSMIG_USE) \
  167. PARSERULE(TEXT("VSAFE"),TEXT("VSAFE *"),pSaveItem,DOSMIG_BAD) \
  168. PARSERULE(TEXT("XCOPY"),TEXT("XCOPY *"),pSaveItem,DOSMIG_USE) \
  169. PARSERULE(TEXT("High"),TEXT("*High *"),pHandleHighFilter,0)
  170. #define CONFIGSYSLIST \
  171. DEFAULTPARSERULE(TEXT("Default Rule"),NULL,pSaveItem,DOSMIG_UNKNOWN) \
  172. PARSERULE(TEXT("Rem"),TEXT("REM *"),pSaveItem,DOSMIG_USE) \
  173. PARSERULE(TEXT("[ (Menu)"),TEXT("[*"),pSaveItem,DOSMIG_USE) \
  174. PARSERULE(TEXT("DEVICE"),TEXT("DEVICE *"),pHandleConfigSysDevice,0) \
  175. PARSERULE(TEXT("INSTALL"),TEXT("INSTALL *"),pHandleConfigSysDevice,0) \
  176. PARSERULE(TEXT("MENUITEM"),TEXT("MENUITEM *"),pSaveItem,DOSMIG_IGNORE) \
  177. PARSERULE(TEXT("MENUDEFAULT"),TEXT("MENUDEFAULT*"),pSaveItem,DOSMIG_IGNORE) \
  178. PARSERULE(TEXT("MENUCOLOR"),TEXT("MENUCOLOR *"),pSaveItem,DOSMIG_IGNORE) \
  179. PARSERULE(TEXT("SUBMENU"),TEXT("SUBMENU *"),pSaveItem,DOSMIG_IGNORE) \
  180. PARSERULE(TEXT("STACKS"),TEXT("STACKS *"),pSaveItem,DOSMIG_IGNORE) \
  181. PARSERULE(TEXT("DOS"),TEXT("DOS *"),pSaveItem,DOSMIG_IGNORE) \
  182. PARSERULE(TEXT("FILES"),TEXT("FILES *"),pSaveItem,DOSMIG_IGNORE) \
  183. PARSERULE(TEXT("SHELL"),TEXT("SHELL *"),pHandleShell,0) \
  184. PARSERULE(TEXT("COUNTRY"),TEXT("COUNTRY *"),pSaveItem,DOSMIG_IGNORE) \
  185. PARSERULE(TEXT("BUFFERS"),TEXT("BUFFERS *"),pSaveItem,DOSMIG_IGNORE) \
  186. PARSERULE(TEXT("BREAK"),TEXT("BREAK *"),pSaveItem,DOSMIG_IGNORE) \
  187. PARSERULE(TEXT("DRIVEPARM"),TEXT("DRIVEPARM *"),pSaveItem,DOSMIG_BAD) \
  188. PARSERULE(TEXT("FCBS"),TEXT("FCBS *"),pSaveItem,DOSMIG_IGNORE) \
  189. PARSERULE(TEXT("INCLUDE"),TEXT("INCLUDE *"),pSaveItem,DOSMIG_IGNORE) \
  190. PARSERULE(TEXT("LASTDRIVE"),TEXT("LASTDRIVE *"),pSaveItem,DOSMIG_IGNORE) \
  191. PARSERULE(TEXT("SET"),TEXT("SET*=*"),pSaveItem,DOSMIG_MIGRATE) \
  192. PARSERULE(TEXT("SET"),TEXT("SET *"),pSaveItem,DOSMIG_MIGRATE) \
  193. PARSERULE(TEXT("SWITCHES"),TEXT("SWITCHES*"),pSaveItem,DOSMIG_IGNORE) \
  194. PARSERULE(TEXT("VERIFY"),TEXT("VERIFY *"),pSaveItem,DOSMIG_USE) \
  195. PARSERULE(TEXT("High"),TEXT("*High *"),pHandleHighFilter,0)
  196. BOOL
  197. InitParser (
  198. VOID
  199. );
  200. VOID
  201. CleanUpParser (
  202. VOID
  203. );
  204. BOOL
  205. ParseLine (
  206. IN PTSTR Line,
  207. IN PPARSERULES ParseRules
  208. );
  209. BOOL
  210. ParseFile (
  211. IN LPCTSTR File,
  212. IN PPARSERULES ParseRules
  213. );
  214. BOOL
  215. ParseDosFiles (
  216. VOID
  217. );
  218. BOOL
  219. ParseEnvironmentVariables (
  220. VOID
  221. );
  222. VOID
  223. BuildParseRules (
  224. VOID
  225. );
  226. /*++
  227. Routine Description:
  228. pGetNextLine retrieves a complete line from the file being processed.
  229. Arguments:
  230. None.
  231. Return Value:
  232. A valid lline from the current file being parsed, or, NULL if there are no
  233. more lines to parse..
  234. --*/
  235. PTSTR
  236. pGetNextLine (
  237. VOID
  238. )
  239. {
  240. PTSTR rLine = NULL;
  241. PTSTR eol = NULL;
  242. MYASSERT(g_LineGrowBuf.Buf);
  243. while (!rLine && g_LineGrowBuf.UserIndex < g_LineGrowBuf.End) {
  244. //
  245. // Set rLine to the current user index within the growbuf.
  246. //
  247. rLine = g_LineGrowBuf.Buf + g_LineGrowBuf.UserIndex;
  248. //
  249. // Walk forward in the growbuf, looking for a \r or \n or the end of the file.
  250. //
  251. eol = _tcschr(rLine, TEXT('\n'));
  252. if(!eol) {
  253. eol = _tcschr(rLine, TEXT('\r'));
  254. }
  255. if (!eol) {
  256. eol = _tcschr(rLine, 26);
  257. }
  258. if (!eol) {
  259. eol = GetEndOfString (rLine);
  260. }
  261. //
  262. // Remember where to start from next time.
  263. //
  264. g_LineGrowBuf.UserIndex = (DWORD) eol - (DWORD) g_LineGrowBuf.Buf + 1;
  265. //
  266. // Now, walk backwards, trimming off all of the white space.
  267. //
  268. do {
  269. *eol = 0;
  270. eol = _tcsdec2(rLine,eol);
  271. } while (eol && _istspace(*eol));
  272. if (!eol) {
  273. //
  274. // This is a blank line. NULL out rLine and get the next line.
  275. //
  276. rLine = NULL;
  277. }
  278. }
  279. g_CurrentLineNumber++;
  280. return rLine;
  281. }
  282. /*++
  283. Routine Description:
  284. pGetFirstLine is responsible for setting up the data structure that will
  285. hold the lines of the file to parse. After setting up the data structure,
  286. pGetFirstLine calls pGetNextLine to return the first line of the file.
  287. Arguments:
  288. FileHandle - Contains a valid file handle opened via CreateFile.
  289. Return Value:
  290. The first complete line of the file being parse, or NULL if there are no
  291. lines, or there was an error..
  292. --*/
  293. PTSTR
  294. pGetFirstLine (
  295. IN HANDLE FileHandle
  296. )
  297. {
  298. DWORD fileSize;
  299. DWORD numBytesRead;
  300. PTSTR rLine = NULL;
  301. MYASSERT(FileHandle != INVALID_HANDLE_VALUE);
  302. g_LineGrowBuf.End = 0;
  303. g_LineGrowBuf.UserIndex = 0;
  304. //
  305. // Get the file size. We'll read the whole file into a grow buf.
  306. //
  307. fileSize = GetFileSize(FileHandle,NULL);
  308. if (fileSize != MAXFILESIZE && fileSize != 0) {
  309. //
  310. // Ensure that the growbuffer is large enough for this file and
  311. // then read the file into it.
  312. //
  313. if (GrowBuffer(&g_LineGrowBuf,fileSize)) {
  314. if (ReadFile(
  315. FileHandle,
  316. g_LineGrowBuf.Buf,
  317. fileSize,
  318. &numBytesRead,
  319. NULL
  320. )) {
  321. //
  322. // Null terminate the whole file..for good measure.
  323. //
  324. *(g_LineGrowBuf.Buf + g_LineGrowBuf.End) = 0;
  325. //
  326. // Now that we have the file in memory, return the first line to the
  327. // caller.
  328. //
  329. rLine = pGetNextLine();
  330. }
  331. else {
  332. LOG((LOG_ERROR,"Dosmig: Error reading from file."));
  333. }
  334. } else {
  335. DEBUGMSG((DBG_ERROR,"Dosmig: Growbuf failure in pGetFirstLine."));
  336. }
  337. }
  338. else {
  339. DEBUGMSG((DBG_WARNING, "Dosmig: File to large to read or empty file... (filesize: %u)",fileSize));
  340. }
  341. return rLine;
  342. }
  343. /*++
  344. Routine Description:
  345. pFindParseRule trys to find a parse rule that matches the line passed in.
  346. The function will first search the regular rules in the PARSERULES
  347. structure passed in. If the line does not match any of the rules found
  348. there, it will return the default rule.
  349. Arguments:
  350. Line - Contains the valid line to try to match with a parse rule.
  351. Rules - Contains a pointer to the set of rules to look through.
  352. Return Value:
  353. The rule that should be used to parse the given line. Since a default rule
  354. is required, this function is guaranteed not to return NULL.
  355. --*/
  356. PPARSERULE
  357. pFindParseRule (
  358. IN PLINESTRUCT LineStruct,
  359. IN PPARSERULES Rules
  360. )
  361. {
  362. PPARSERULE rRule = NULL;
  363. PTSTR matchLine = NULL;
  364. MYASSERT(LineStruct && Rules && Rules -> DefaultRule);
  365. rRule = Rules -> RuleList;
  366. //
  367. // Minor kludge here: The parse code uses pattern matches with rules that look
  368. // something like: "REM *" for example. This pattern depends on there being at least
  369. // one bit of white space after a REM statement. Unfortunately, a line such as
  370. // "REM" is entirely possible in the growbuf (Line). So, we actually perform the match
  371. // against the line with an extra space added.
  372. //
  373. matchLine = JoinText(LineStruct -> Command,TEXT(" "));
  374. if (matchLine) {
  375. while (rRule && !IsPatternMatch(rRule -> Pattern, matchLine)) {
  376. rRule = rRule -> Next;
  377. }
  378. if (!rRule) {
  379. rRule = Rules -> DefaultRule;
  380. }
  381. FreeText(matchLine);
  382. }
  383. return rRule;
  384. }
  385. /*++
  386. Routine Description:
  387. InitParser is responsible for doing any one-time initialization of the
  388. parser. It should be called only once, before any parsing is done.
  389. Arguments:
  390. None.
  391. Return Value:
  392. TRUE if the parser was successfully initialized, FALSE otherwise.
  393. --*/
  394. BOOL
  395. InitParser (
  396. VOID
  397. )
  398. {
  399. BOOL rSuccess = TRUE;
  400. if (g_ToolMode) {
  401. g_DosMigPool = PoolMemInitNamedPool ("DosMig");
  402. }
  403. return rSuccess;
  404. }
  405. /*++
  406. Routine Description:
  407. CleanUpParser is responsible for doing any one time cleanup of the parser.
  408. It should be called after all parsing is done.
  409. Arguments:
  410. None.
  411. Return Value:
  412. --*/
  413. VOID
  414. CleanUpParser (
  415. VOID
  416. )
  417. {
  418. if (g_ToolMode) {
  419. PoolMemDestroyPool (g_DosMigPool);
  420. }
  421. FreeGrowBuffer(&g_LineGrowBuf);
  422. FreeGrowBuffer(&g_ExtraPaths);
  423. }
  424. BOOL
  425. pEnsurePathHasExecutableExtension (
  426. OUT PTSTR NewPath,
  427. IN PTSTR OldPath,
  428. IN PTSTR File OPTIONAL
  429. )
  430. {
  431. BOOL rSuccess = FALSE;
  432. PCTSTR p = NULL;
  433. WIN32_FIND_DATA findData;
  434. HANDLE h = INVALID_HANDLE_VALUE;
  435. StringCopy(NewPath,OldPath);
  436. if (File) {
  437. AppendPathWack(NewPath);
  438. StringCat(NewPath,File);
  439. }
  440. StringCat(NewPath,TEXT("*"));
  441. if ((h=FindFirstFile(NewPath,&findData)) != INVALID_HANDLE_VALUE) {
  442. do {
  443. p = GetFileExtensionFromPath(findData.cFileName);
  444. if (p) {
  445. if (StringIMatch(p,TEXT("exe")) ||
  446. StringIMatch(p,TEXT("bat")) ||
  447. StringIMatch(p,TEXT("com")) ||
  448. StringIMatch(p,TEXT("sys"))) {
  449. p = _tcsrchr(NewPath,TEXT('\\'));
  450. MYASSERT (p);
  451. if (p) {
  452. StringCopy(
  453. _tcsinc(p),
  454. *findData.cAlternateFileName ? findData.cAlternateFileName : findData.cFileName
  455. );
  456. FindClose(h);
  457. rSuccess = TRUE;
  458. break;
  459. }
  460. }
  461. }
  462. } while (FindNextFile(h,&findData));
  463. }
  464. return rSuccess;
  465. }
  466. BOOL
  467. pGetFullPath (
  468. IN OUT PLINESTRUCT LineStruct
  469. )
  470. {
  471. BOOL rSuccess = TRUE;
  472. PATH_ENUM e;
  473. HANDLE h = INVALID_HANDLE_VALUE;
  474. BOOL pathFound = FALSE;
  475. if (StringIMatch(LineStruct -> Path, LineStruct -> Command)) {
  476. //
  477. // No path information was stored in the config line. We have to find the full path ourselves.
  478. //
  479. if (EnumFirstPath (&e, g_ExtraPaths.Buf, NULL, NULL)) {
  480. do {
  481. rSuccess = pEnsurePathHasExecutableExtension(LineStruct -> FullPath, e.PtrCurrPath, LineStruct -> Command);
  482. if (rSuccess) {
  483. EnumPathAbort(&e);
  484. break;
  485. }
  486. } while (EnumNextPath(&e));
  487. }
  488. }
  489. else {
  490. //
  491. // A full path name was specified in the line. Now all we need to do is ensure that it includes the extension.
  492. //
  493. rSuccess = pEnsurePathHasExecutableExtension(LineStruct -> FullPath, LineStruct -> Path, NULL);
  494. }
  495. return rSuccess;
  496. }
  497. VOID
  498. InitLineStruct (
  499. OUT PLINESTRUCT LineStruct,
  500. IN PTSTR Line
  501. )
  502. {
  503. BOOL inQuotes = FALSE;
  504. PTSTR p = NULL;
  505. TCHAR oldChar;
  506. TCHAR ntPath[MEMDB_MAX];
  507. static TCHAR extraPath[MEMDB_MAX] = "";
  508. MYASSERT(Line);
  509. ZeroMemory(LineStruct,sizeof(LINESTRUCT));
  510. //
  511. // If line is empty, we are done..
  512. //
  513. if (!*Line) {
  514. return;
  515. }
  516. //
  517. // Save away a copy of the full line.
  518. //
  519. StringCopy(LineStruct -> FullLine,Line);
  520. //
  521. // Seperate the path and the arguments.
  522. //
  523. p = Line;
  524. while(!*LineStruct -> Path) {
  525. if (!*p) {
  526. StringCopy(LineStruct -> Path,Line);
  527. break;
  528. }
  529. if (*p == TEXT('"')) {
  530. inQuotes = !inQuotes;
  531. }
  532. if ((*p == TEXT(' ') && !inQuotes) || *p == TEXT('=')) {
  533. //
  534. // reached the end of the command/path part of the string.
  535. //
  536. oldChar = *p;
  537. *p = 0;
  538. StringCopy(LineStruct -> Path,Line);
  539. *p = oldChar;
  540. StringCopy(LineStruct -> Arguments,p);
  541. break;
  542. }
  543. p = _tcsinc(p);
  544. }
  545. //
  546. // Grab the actual command.
  547. //
  548. p = _tcsrchr(LineStruct -> Path,TEXT('\\'));
  549. if (p) {
  550. StringCopy(LineStruct -> Command,_tcsinc(p));
  551. }
  552. else {
  553. StringCopy(LineStruct -> Command,LineStruct -> Path);
  554. }
  555. //
  556. // We need to find the fully qualified path, with extension, and if that path will change on NT.
  557. //
  558. if (!pGetFullPath(LineStruct)) {
  559. DEBUGMSG((DBG_VERBOSE,"Could not get full path for %s.",LineStruct -> FullLine));
  560. StringCopy(LineStruct -> FullPath,LineStruct -> Path);
  561. LineStruct -> StatusOnNt = FILESTATUS_UNCHANGED;
  562. }
  563. else {
  564. LineStruct -> StatusOnNt = GetFileInfoOnNt(LineStruct -> FullPath, ntPath, MEMDB_MAX);
  565. }
  566. //
  567. // We only change the line if it is moved on NT and they specified a path before.
  568. //
  569. if ((LineStruct -> StatusOnNt & FILESTATUS_MOVED) && (!StringIMatch(LineStruct -> Path, LineStruct -> Command))) {
  570. StringCopy(LineStruct -> PathOnNt,ntPath);
  571. }
  572. else {
  573. StringCopy(LineStruct -> PathOnNt,LineStruct -> Path);
  574. }
  575. }
  576. /*++
  577. Routine Description:
  578. ParseLine parses a single line of a text using the provided parse rules.
  579. Arguments:
  580. Line - Contains a valid string that the caller wishes to be
  581. parsed.
  582. ParseRules - Points to the list of rules to use in parsing the provided
  583. line.
  584. Return Value:
  585. TRUE if the line was successfully parsed, FALSE
  586. otherwise.
  587. --*/
  588. BOOL
  589. ParseLine (
  590. IN PTSTR Line,
  591. IN PPARSERULES ParseRules
  592. )
  593. {
  594. BOOL rSuccess = FALSE;
  595. PPARSERULE rule;
  596. LINESTRUCT ls;
  597. InitLineStruct(&ls,Line);
  598. //
  599. // Look for a match in the parse rules. call the matching rule.
  600. // If no match is found, call the default rule.
  601. //
  602. rule = pFindParseRule(&ls,ParseRules);
  603. if (rule) {
  604. rSuccess = (rule -> Handle)(&ls,rule -> Parameter);
  605. DEBUGMSG_IF ((!rSuccess,DBG_ERROR,"The %s rule reported an error parsing the line:\n\t%s",rule -> Name, Line));
  606. if (!rSuccess) {
  607. LOG ((
  608. LOG_WARNING,
  609. "There was an error processing the line %s in the file %s. "
  610. "There could be problems associated with this file after migration.",
  611. Line,
  612. g_CurrentFile
  613. ));
  614. }
  615. }
  616. return rSuccess;
  617. }
  618. /*++
  619. Routine Description:
  620. ParseFile parses an entire file using the provided parse rules.
  621. Arguments:
  622. File - The path of a file that the caller wishes parsed.
  623. ParseRules - Points to the list of rules to use in parsing this file.
  624. Return Value:
  625. TRUE if the file was successfully parsed, FALSE otherwise.
  626. --*/
  627. BOOL
  628. ParseFile (
  629. IN LPCTSTR File,
  630. IN PPARSERULES ParseRules
  631. )
  632. {
  633. BOOL rSuccess = TRUE;
  634. HANDLE fileHandle;
  635. PTSTR line;
  636. MYASSERT(File);
  637. MYASSERT(ParseRules);
  638. DEBUGMSG((DBG_DOSMIG,"Parsing file %s. Parse rules: %s",File,ParseRules -> Name));
  639. //
  640. // Initialize global per file parse variables.
  641. //
  642. g_CurrentFile = File;
  643. g_CurrentLineNumber = 0;
  644. g_CurrentLine = NULL;
  645. //
  646. // Open File for parsing
  647. //
  648. fileHandle = CreateFile(
  649. File,
  650. GENERIC_READ,
  651. FILE_SHARE_READ,
  652. NULL, // Handle cannot be inherited.
  653. OPEN_EXISTING,
  654. FILE_ATTRIBUTE_NORMAL,
  655. NULL // No template file.
  656. );
  657. if (fileHandle != INVALID_HANDLE_VALUE) {
  658. //
  659. // Parse each line of the file.
  660. //
  661. line = pGetFirstLine(fileHandle);
  662. if (line) {
  663. do {
  664. //
  665. // Save the current line away.
  666. //
  667. g_CurrentLine = line;
  668. if (SizeOfString (line) <= MEMDB_MAX) {
  669. ParseLine(line,ParseRules);
  670. } else {
  671. SetLastError (ERROR_SUCCESS);
  672. LOG((LOG_ERROR, "Line too long in %s; setup will not migrate it", File));
  673. }
  674. //
  675. // Get the next line.
  676. //
  677. line = pGetNextLine();
  678. } while (line && rSuccess);
  679. }
  680. CloseHandle(fileHandle);
  681. }
  682. ELSE_DEBUGMSG((DBG_WARNING,"Could not open file %s for parsing. ",File));
  683. return rSuccess;
  684. }
  685. VOID
  686. pAddMessage (
  687. IN UINT Type,
  688. IN UINT LineNumber,
  689. IN PCTSTR File,
  690. IN PCTSTR Line,
  691. IN PCTSTR Path
  692. )
  693. {
  694. TCHAR lineNumberString[20];
  695. UINT messageId;
  696. PCTSTR message;
  697. PCTSTR totalMessage;
  698. PCTSTR argArray[3];
  699. //
  700. // if this is the first message found, add a report message. In any case, add
  701. // a message to the setupact.log.
  702. //
  703. if (!g_IncompatibilityDetected) {
  704. /*
  705. Don't Display this message -- It just confuses users without offering any real information.
  706. baseGroup = GetStringResource(MSG_INSTALL_NOTES_ROOT);
  707. subGroup = GetStringResource(MSG_DOS_WARNING_SUBGROUP);
  708. message = GetStringResource(MSG_DOS_WARNING);
  709. if (baseGroup && subGroup && message) {
  710. group = JoinPaths(baseGroup,subGroup);
  711. MsgMgr_ObjectMsg_Add (
  712. Path,
  713. group,
  714. message
  715. );
  716. }
  717. if (message) {
  718. FreeStringResource(message);
  719. }
  720. if (subGroup) {
  721. FreeStringResource(subGroup);
  722. }
  723. if (baseGroup) {
  724. FreeStringResource(baseGroup);
  725. }
  726. if (group) {
  727. FreePathString(group);
  728. }
  729. */
  730. g_IncompatibilityDetected = TRUE;
  731. }
  732. messageId = Type == DOSMIG_BAD ? MSG_DOS_INCOMPATIBLE_ITEM : MSG_DOS_UNKNOWN_ITEM;
  733. //
  734. // Prepare message
  735. //
  736. wsprintf(lineNumberString,"%u",LineNumber);
  737. argArray[0] = lineNumberString,
  738. argArray[1] = File;
  739. argArray[2] = Line;
  740. message = ParseMessageID(messageId,argArray);
  741. if (message) {
  742. totalMessage=GrowBuffer(&g_IncompatibilityBuffer,SizeOfString(message) + 2);
  743. if (totalMessage) {
  744. StringCopy( (PTSTR) (g_IncompatibilityBuffer.Buf + g_IncompatibilityBuffer.UserIndex), message);
  745. StringCat( (PTSTR) (g_IncompatibilityBuffer.Buf + g_IncompatibilityBuffer.UserIndex), TEXT("\r\n"));
  746. g_IncompatibilityBuffer.UserIndex += ByteCount (message) + 2;
  747. }
  748. FreeStringResource(message);
  749. }
  750. }
  751. /*++
  752. Routine Description:
  753. pSaveItem is a common routine that saves a line into memdb along with the
  754. information that dosmignt will need to successfully migrate the line in GUI
  755. mode. Depending on the type of the line, this function may also add an
  756. incompatibility message to memdb.
  757. Arguments:
  758. Line - A valid line of text. The current line being parsed. Note that this
  759. line may have been altered through parse rules and thus be different
  760. than g_CurrentLine. g_CurrentLine is what is saved into memdb, this
  761. parameter is ignored.
  762. Type - The type of the line. This information is saved into memdb where it
  763. will be used by dosmignt during GUI mode processing. Type is also
  764. used to trigger incompatibility messages, if necessary.
  765. Return Value:
  766. TRUE if the line was successfully saved, FALSE otherwise.
  767. --*/
  768. BOOL
  769. pSaveItem (
  770. IN PLINESTRUCT LineStruct,
  771. IN DWORD Type
  772. )
  773. {
  774. BOOL rSuccess = TRUE;
  775. static DWORD enumerator = 0;
  776. TCHAR enumString[20];
  777. TCHAR key[MEMDB_MAX];
  778. TCHAR lineToSave[MEMDB_MAX];
  779. MYASSERT(LineStruct);
  780. //
  781. // First, save away all of the information into memdb. We'll need it on the NT side.
  782. //
  783. wsprintf(enumString,TEXT("%07u"),enumerator++);
  784. //
  785. // Fix up the g_CurrentLine as necessary..
  786. //
  787. StringCopy(lineToSave,g_CurrentLine);
  788. if (!StringIMatch(LineStruct -> Path, LineStruct -> Command)) {
  789. //
  790. // path was specified..
  791. //
  792. if (!StringIMatch(LineStruct -> Path,LineStruct -> PathOnNt)) {
  793. //
  794. // Different path on NT..
  795. //
  796. StringSearchAndReplace(lineToSave,LineStruct -> Path,LineStruct -> PathOnNt);
  797. }
  798. }
  799. //
  800. // Build the key for this line (can't use the EX Memdb calls since we are setting userflags..)
  801. //
  802. MemDbBuildKey(key,MEMDB_CATEGORY_DM_LINES,enumString,NULL,lineToSave);
  803. rSuccess = MemDbSetValueAndFlags(key,g_CurrentFileOffset,(WORD) Type,0);
  804. //
  805. // Now, if the passed in parameter was either unknown or bad, we need to add a message to the
  806. // message manager.
  807. //
  808. if (Type == DOSMIG_BAD || Type == DOSMIG_UNKNOWN) {
  809. pAddMessage(Type,g_CurrentLineNumber,g_CurrentFile,g_CurrentLine,LineStruct -> FullPath);
  810. }
  811. return rSuccess;
  812. }
  813. BOOL
  814. pHandleMSCDEX (
  815. IN PLINESTRUCT LineStruct,
  816. DWORD Parameter
  817. )
  818. {
  819. BOOL rSuccess = TRUE;
  820. PCTSTR driveSwitch = NULL;
  821. TCHAR driveLetter;
  822. TCHAR driveString[20];
  823. //
  824. // This function is a minor kludge. MSCDEX can assign a drive letter to real mode
  825. // cd roms.. Since it is handled in dos files instead of the registry, the code
  826. // that is supposed to collect this information (drvlettr.c) does not have a chance.
  827. // We will catch this case and save it into the winnt.sif file just as drvlettr.c
  828. // would have.
  829. //
  830. driveSwitch = _tcsistr(LineStruct -> Arguments,TEXT("/l:"));
  831. if (driveSwitch) {
  832. //
  833. // This mscdex line is one of the one's we care about.
  834. //
  835. driveLetter = *(driveSwitch + 3);
  836. if (driveLetter) {
  837. DEBUGMSG((DBG_DOSMIG,"Drive letter information is contained in the line %s. Preserving it. (%c)", LineStruct -> FullLine,driveLetter));
  838. wsprintf(driveString,TEXT("%u"),toupper(driveLetter) - TEXT('A'));
  839. rSuccess &= WriteInfKey(WINNT_D_WIN9XDRIVES,driveString,TEXT("5,"));
  840. DEBUGMSG_IF((!rSuccess,DBG_ERROR,"Unable to save drive letter information for line %s.",LineStruct -> FullLine));
  841. }
  842. }
  843. //
  844. // Go ahead and save this into memdb.
  845. //
  846. rSuccess &= pSaveItem(LineStruct,DOSMIG_IGNORE);
  847. return rSuccess;
  848. }
  849. /*++
  850. Routine Description:
  851. pHandleAtSign takes care of lines that begin with the '@' symbol. The
  852. symbol is trimmed of f of the line and this modified line is parsed again.
  853. Arguments:
  854. Line - Contains the valid line that is currently being parsed.
  855. Parameter - This parameter is unused.
  856. Return Value:
  857. TRUE if the function completed successfully, FALSE otherwise.
  858. --*/
  859. BOOL
  860. pHandleAtSign (
  861. IN PLINESTRUCT LineStruct,
  862. DWORD Parameter
  863. )
  864. {
  865. BOOL rSuccess = TRUE;
  866. TCHAR buffer[MEMDB_MAX];
  867. MYASSERT(_tcschr(LineStruct -> FullLine,TEXT('@')));
  868. StringCopy(buffer,_tcsinc(_tcschr(LineStruct -> FullLine,TEXT('@'))));
  869. rSuccess = ParseLine(buffer,&g_BatchFileRules);
  870. return rSuccess;
  871. }
  872. /*++
  873. Routine Description:
  874. pHandleLoadHigh - Is responsible for handling the "loadhigh" and "lh" dos
  875. statements. It simply skips past these statements and calls parseline on
  876. the remainder of the line.
  877. Arguments:
  878. Line - Contains the valid line that is currently being parsed.
  879. Parameter - This parameter is unused.
  880. Return Value:
  881. TRUE if the function completed successfully, FALSE otherwise.
  882. --*/
  883. BOOL
  884. pHandleLoadHigh (
  885. IN PLINESTRUCT LineStruct,
  886. DWORD Parameter
  887. )
  888. {
  889. BOOL rSuccess = TRUE;
  890. TCHAR buffer[MEMDB_MAX];
  891. PCTSTR p;
  892. p = _tcschr(LineStruct -> Arguments, TEXT(' '));
  893. if (!p) {
  894. return FALSE;
  895. }
  896. buffer[0] = 0;
  897. StringCopy(buffer,SkipSpace(p));
  898. rSuccess = ParseLine(buffer,&g_BatchFileRules);
  899. return rSuccess;
  900. }
  901. /*++
  902. Routine Description:
  903. pHandleCall takes care of call statements in batch files. It saves these
  904. lines to memdb and adds the file mentioned in the call statement to the
  905. list of files to be parsed.
  906. Arguments:
  907. Line - Contains the valid line that is currently being parsed.
  908. Parameter - This parameter is unused.
  909. Return Value:
  910. TRUE if the function completed successfully, FALSE otherwise.
  911. --*/
  912. BOOL
  913. pHandleCall (
  914. IN PLINESTRUCT LineStruct,
  915. DWORD Parameter
  916. )
  917. {
  918. BOOL rSuccess = TRUE;
  919. LINESTRUCT ls;
  920. rSuccess = pSaveItem(LineStruct,DOSMIG_USE);
  921. InitLineStruct (&ls, (PTSTR) SkipSpace (LineStruct -> Arguments));
  922. if (!GrowListAppendString(&g_FileList,ls.FullPath)) {
  923. rSuccess = FALSE;
  924. }
  925. return rSuccess;
  926. }
  927. /*++
  928. Routine Description:
  929. pHandleConfigSysDevice is responsible for device and devicehigh statements
  930. in config.sys. The function extracts the driver from the line and tries to
  931. determine if the compatibility of that driver. The line is eventually
  932. written to memdb.
  933. Arguments:
  934. Line - Contains the valid line that is currently being parsed.
  935. Parameter - This parameter is unused.
  936. Return Value:
  937. TRUE if the function completed successfully, FALSE otherwise.
  938. --*/
  939. BOOL
  940. pHandleConfigSysDevice (
  941. IN PLINESTRUCT LineStruct,
  942. DWORD Parameter
  943. )
  944. {
  945. BOOL rSuccess = TRUE;
  946. TCHAR buffer[MEMDB_MAX];
  947. PCTSTR p;
  948. //
  949. // looks like there ARE config.sys files with INSTALLHIGH "driver",
  950. // without "equal" sign (like INSTALLHIGH driver, and not INSTALLHIGH=driver)
  951. p = SkipSpace(LineStruct -> Arguments);
  952. if (_tcsnextc (p) == TEXT('=')) {
  953. p = SkipSpace (p + 1);
  954. }
  955. StringCopy(buffer, p);
  956. return ParseLine(buffer, &g_BatchFileRules);
  957. }
  958. DWORD
  959. pGetLineTypeFromNtStatusAndPath (
  960. IN DWORD Status,
  961. IN PCTSTR Path
  962. )
  963. {
  964. DWORD unused;
  965. DWORD rType = DOSMIG_UNKNOWN;
  966. if (Status & (FILESTATUS_MOVED | FILESTATUS_REPLACED)) {
  967. rType = DOSMIG_USE;
  968. } else if (Status & FILESTATUS_DELETED) {
  969. rType = DOSMIG_IGNORE;
  970. } else {
  971. if (IsFileMarkedAsHandled (Path)) {
  972. rType = DOSMIG_IGNORE;
  973. }else if (IsReportObjectHandled(Path)) {
  974. rType = DOSMIG_USE;
  975. } else if (MemDbGetOffsetEx(MEMDB_CATEGORY_COMPATIBLE_DOS,Path,NULL,NULL,&unused)) {
  976. rType = DOSMIG_USE;
  977. } else if (MemDbGetOffsetEx(MEMDB_CATEGORY_DEFERREDANNOUNCE,Path,NULL,NULL,&unused)) {
  978. rType = DOSMIG_IGNORE;
  979. }
  980. }
  981. return rType;
  982. }
  983. BOOL
  984. pHandleShell (
  985. IN PLINESTRUCT LineStruct,
  986. DWORD Parameter
  987. )
  988. {
  989. PTSTR p=LineStruct->Arguments;
  990. LINESTRUCT ls;
  991. TCHAR buffer[MEMDB_MAX];
  992. UINT lineType;
  993. if (p) {
  994. p = _tcsinc (p);
  995. }
  996. else {
  997. return pSaveItem (LineStruct, DOSMIG_IGNORE);
  998. }
  999. InitLineStruct (&ls, p);
  1000. lineType = pGetLineTypeFromNtStatusAndPath (ls.StatusOnNt, ls.FullPath);
  1001. if (lineType == DOSMIG_USE) {
  1002. //
  1003. // Fix up the line and save it back.
  1004. //
  1005. wsprintf(buffer, TEXT("SHELL=%s %s"), ls.PathOnNt, ls.Arguments ? ls.Arguments : S_EMPTY);
  1006. g_CurrentLine = PoolMemDuplicateString (g_DosMigPool, buffer);
  1007. }
  1008. return pSaveItem (LineStruct, lineType);
  1009. }
  1010. /*++
  1011. Routine Description:
  1012. pHandleUnknownBatLine _tries_ to deal with any line that is not caught by
  1013. another explicit rule...The first thing it will do is see if the line
  1014. starts with a path containing *.bat. If so, it will add that bat file to
  1015. the list to be parsed. If the file does not end with *.bat, then, the
  1016. function will assume that this is a tsr and attempt to determine its
  1017. compatibility.
  1018. Arguments:
  1019. Line - Contains the valid line that is currently being parsed.
  1020. Parameter - This parameter is unused.
  1021. Return Value:
  1022. TRUE if the function completed successfully, FALSE otherwise.
  1023. --*/
  1024. BOOL
  1025. pHandleUnknownBatLine (
  1026. IN PLINESTRUCT LineStruct,
  1027. DWORD Parameter
  1028. )
  1029. {
  1030. BOOL rSuccess = TRUE;
  1031. DWORD lineType = DOSMIG_UNKNOWN;
  1032. DEBUGMSG((DBG_DOSMIG,"Processing unknown bat line...%s.",LineStruct -> FullLine));
  1033. //
  1034. // First, see if this is a *.bat file..
  1035. //
  1036. if (IsPatternMatch(TEXT("*.bat"),LineStruct -> Command)) {
  1037. //
  1038. // This is another batch file..add it to those to be parsed..
  1039. //
  1040. DEBUGMSG((DBG_DOSMIG,"...The line is a batch file. Add it to those to be parsed.."));
  1041. if (!GrowListAppendString(&g_FileList,LineStruct -> FullLine)) {
  1042. rSuccess = FALSE;
  1043. }
  1044. lineType = DOSMIG_USE;
  1045. }
  1046. //
  1047. // See if they are changing the drive.
  1048. //
  1049. if (IsPatternMatch(TEXT("?:"),LineStruct->Command)) {
  1050. lineType = DOSMIG_USE;
  1051. }
  1052. if (lineType == DOSMIG_UNKNOWN) {
  1053. //
  1054. // Still don't know what the line is. Lets check its status on NT. if it is moved ore replaced,
  1055. // we'll just change the path if necessary, and use it. Otherwise,
  1056. //
  1057. lineType = pGetLineTypeFromNtStatusAndPath (LineStruct->StatusOnNt, LineStruct->FullPath);
  1058. }
  1059. //
  1060. // In anycase, save away the line in memdb.
  1061. //
  1062. rSuccess &= pSaveItem(LineStruct,lineType);
  1063. return rSuccess;
  1064. }
  1065. /*++
  1066. Routine Description:
  1067. pHandleHighFilter - Is responsible for handling the "*high" statements
  1068. besides LoadHigh and lh.
  1069. Arguments:
  1070. Line - Contains the valid line that is currently being parsed.
  1071. Parameter - This parameter is unused.
  1072. Return Value:
  1073. TRUE if the function completed successfully, FALSE otherwise.
  1074. --*/
  1075. BOOL
  1076. pHandleHighFilter (
  1077. IN PLINESTRUCT LineStruct,
  1078. DWORD Parameter
  1079. )
  1080. {
  1081. PTSTR p;
  1082. BOOL rSuccess = TRUE;
  1083. if (!StringIMatch (LineStruct->Command, LineStruct->FullPath)) {
  1084. return pHandleUnknownBatLine (LineStruct, Parameter);
  1085. }
  1086. _tcslwr (LineStruct->FullLine);
  1087. p = _tcsstr (LineStruct->FullLine,TEXT("high"));
  1088. if (!p || p == LineStruct->FullLine) {
  1089. return pHandleUnknownBatLine (LineStruct, Parameter);
  1090. }
  1091. *p = 0;
  1092. p = JoinTextEx (NULL, LineStruct->FullLine, p + 4, TEXT(""), 0, NULL);
  1093. rSuccess = ParseLine (p, g_CurrentRules);
  1094. FreeText (p);
  1095. return rSuccess;
  1096. }
  1097. /*++
  1098. Routine Description:
  1099. pAddRuleToList creates a PARSERULE out of the parameters passed in and adds
  1100. it to the List provided by the caller.
  1101. Arguments:
  1102. Name - The name of the parse rule.
  1103. Pattern - The pattern for this parse rule
  1104. Function - The function to call when this rule is hit.
  1105. Parameter - The extra parameter data to pass to the function when this rule
  1106. is hit.
  1107. List - This list of rules to add the new parse rule to.
  1108. Return Value:
  1109. TRUE if the rule was successfully added, FALSE
  1110. otherwise.
  1111. --*/
  1112. BOOL
  1113. pAddRuleToList (
  1114. PCTSTR Name,
  1115. PCTSTR Pattern,
  1116. RULEFUNC * Function,
  1117. DWORD Parameter,
  1118. PPARSERULE * List
  1119. )
  1120. {
  1121. BOOL rSuccess = TRUE;
  1122. PPARSERULE newRule = NULL;
  1123. PPARSERULE curRule = NULL;
  1124. MYASSERT(List);
  1125. MYASSERT(Function);
  1126. MYASSERT(Name);
  1127. //
  1128. // Allocate memory for the new rule.
  1129. //
  1130. newRule = PoolMemGetMemory(g_DosMigPool,sizeof(PARSERULE));
  1131. if (newRule) {
  1132. //
  1133. // Fill in the new rule.
  1134. //
  1135. newRule -> Name = Name;
  1136. newRule -> Pattern = Pattern;
  1137. newRule -> Handle = Function;
  1138. newRule -> Parameter = Parameter;
  1139. newRule -> Next = NULL;
  1140. //
  1141. // Attach the rule into the provided list.
  1142. //
  1143. if (!*List) {
  1144. *List = newRule;
  1145. }
  1146. else {
  1147. curRule = *List;
  1148. while (curRule -> Next) {
  1149. curRule = curRule -> Next;
  1150. }
  1151. curRule -> Next = newRule;
  1152. }
  1153. }
  1154. ELSE_DEBUGMSG((DBG_ERROR,"Not enough memory to create rule."));
  1155. return rSuccess;
  1156. }
  1157. /*++
  1158. Routine Description:
  1159. pBuildParseRules builds the rule lists for config.sys and autoexec.bat
  1160. files.
  1161. Arguments:
  1162. None.
  1163. Return Value:
  1164. None.
  1165. --*/
  1166. VOID
  1167. pBuildParseRules (
  1168. VOID
  1169. )
  1170. {
  1171. #define DEFAULTPARSERULE(Name,Pattern,Function,Parameter) \
  1172. pAddRuleToList(Name,Pattern,Function,Parameter,&(curRules -> DefaultRule));
  1173. #define PARSERULE(Name,Pattern,Function,Parameter) \
  1174. pAddRuleToList(Name,Pattern,Function,Parameter,&(curRules -> RuleList));
  1175. PPARSERULES curRules = NULL;
  1176. //
  1177. // Create config sys rules.
  1178. //
  1179. curRules = &g_ConfigSysRules;
  1180. curRules -> Name = TEXT("Config.sys Rules");
  1181. CONFIGSYSLIST;
  1182. //
  1183. // Create batch file rules.
  1184. //
  1185. curRules = &g_BatchFileRules;
  1186. curRules -> Name = TEXT("Batch File Rules");
  1187. BATCHFILELIST;
  1188. }
  1189. /*++
  1190. Routine Description:
  1191. ParseDosFiles is the function which handles the parsing of legacy
  1192. configuration files (config.sys and batch files...)
  1193. Arguments:
  1194. None.
  1195. Return Value:
  1196. True if the files were successfully parsed, FALSE
  1197. otherwise.
  1198. --*/
  1199. BOOL
  1200. ParseDosFiles (
  1201. VOID
  1202. )
  1203. {
  1204. BOOL rSuccess = TRUE;
  1205. PCTSTR curFile;
  1206. DWORD curIndex = 0;
  1207. TCHAR autoexecPath[] = S_AUTOEXECPATH;
  1208. TCHAR configsysPath[] = S_CONFIGSYSPATH;
  1209. PTSTR p;
  1210. //
  1211. // Initialize the parser.
  1212. //
  1213. if (InitParser()) {
  1214. //
  1215. // build the lists of parse rules.
  1216. //
  1217. pBuildParseRules();
  1218. //
  1219. // Update drive letter
  1220. //
  1221. autoexecPath[0] = g_BootDriveLetter;
  1222. configsysPath[0] = g_BootDriveLetter;
  1223. p = _tcschr(autoexecPath, TEXT('a'));
  1224. *p = 0;
  1225. GrowBufAppendString(&g_ExtraPaths,autoexecPath);
  1226. *p = TEXT('a');
  1227. //
  1228. // Add config.sys and autoexec.bat to the list of files to parse.
  1229. //
  1230. GrowListAppendString(&g_FileList,configsysPath);
  1231. GrowListAppendString(&g_FileList,autoexecPath);
  1232. //
  1233. // Now, parse the files in the list. Note that additional files may be added
  1234. // to the list as a result of parsing. (i.e. by finding a call statement.)
  1235. //
  1236. while (curFile = GrowListGetString(&g_FileList,curIndex++)) {
  1237. if (DoesFileExist (curFile)) {
  1238. //
  1239. // Save the file into memdb.
  1240. //
  1241. MemDbSetValueEx(MEMDB_CATEGORY_DM_FILES,NULL,NULL,curFile,0,&g_CurrentFileOffset);
  1242. //
  1243. // parse the file using config.sys parse rules if the file is config.sys and
  1244. // the batch file parse rules otherwise.
  1245. //
  1246. if (StringIMatch(configsysPath,curFile)) {
  1247. g_CurrentRules = &g_ConfigSysRules;
  1248. rSuccess &= ParseFile(curFile,&g_ConfigSysRules);
  1249. }
  1250. else {
  1251. g_CurrentRules = &g_BatchFileRules;
  1252. rSuccess &= ParseFile(curFile,&g_BatchFileRules);
  1253. }
  1254. }
  1255. ELSE_DEBUGMSG((DBG_DOSMIG,"The path %s does not exist. This file will not be processed.", curFile));
  1256. }
  1257. //
  1258. // There was an incompatibility detected. Write the incompatibility buffer to the log.
  1259. //
  1260. if (g_IncompatibilityDetected) {
  1261. LOG ((LOG_WARNING, (PCSTR)MSG_DOS_LOG_WARNING, g_IncompatibilityBuffer.Buf));
  1262. }
  1263. //
  1264. // Cleanup resources.
  1265. //
  1266. FreeGrowBuffer(&g_IncompatibilityBuffer);
  1267. FreeGrowList(&g_FileList);
  1268. CleanUpParser();
  1269. }
  1270. return rSuccess;
  1271. }
  1272. #define S_PATH_PATTERN TEXT("Path*")
  1273. BOOL
  1274. ParseEnvironmentVariables (
  1275. VOID
  1276. )
  1277. {
  1278. BOOL rSuccess = TRUE;
  1279. PVOID envVars = NULL;
  1280. PTSTR line = NULL;
  1281. MULTISZ_ENUM e;
  1282. LINESTRUCT ls;
  1283. PTSTR p;
  1284. HASHTABLE excludeTable = NULL;
  1285. HASHITEM hashResult;
  1286. envVars = GetEnvironmentStrings();
  1287. __try {
  1288. if (!envVars) {
  1289. LOG((
  1290. LOG_WARNING,
  1291. "Unable to retrieve environment variables. "
  1292. "Some environment variables may not be migrated correctly. "
  1293. "rc from GetEnvironmentStrings: %u",
  1294. GetLastError()
  1295. ));
  1296. return FALSE;
  1297. }
  1298. //
  1299. // Set fake name of file for envvars.
  1300. //
  1301. MemDbSetValueEx (MEMDB_CATEGORY_DM_FILES, NULL, NULL, S_ENVVARS, 0, &g_CurrentFileOffset);
  1302. //
  1303. // Enumerate through each of the environment variables and save them away for migration.
  1304. //
  1305. if (EnumFirstMultiSz (&e, envVars)) {
  1306. //
  1307. // Create list of environment variables to skip.
  1308. //
  1309. excludeTable = HtAlloc ();
  1310. MYASSERT (excludeTable);
  1311. HtAddString (excludeTable, TEXT("path"));
  1312. HtAddString (excludeTable, TEXT("comspec"));
  1313. HtAddString (excludeTable, TEXT("cmdline"));
  1314. ZeroMemory(&ls,sizeof(LINESTRUCT));
  1315. do {
  1316. p = _tcschr (e.CurrentString, TEXT('='));
  1317. //
  1318. // Get rid of empty environment strings or the dummy env string starting
  1319. // with '='
  1320. //
  1321. if (!p || p == e.CurrentString) {
  1322. continue;
  1323. }
  1324. *p = 0;
  1325. hashResult = HtFindString (excludeTable, e.CurrentString);
  1326. *p = TEXT('=');
  1327. if (!hashResult) {
  1328. //
  1329. // This is a good environment string. As long as the length is ok, lets migrate it.
  1330. //
  1331. line = JoinTextEx (NULL, TEXT("SET"), e.CurrentString, TEXT(" "), 0, NULL);
  1332. if (line) {
  1333. if (CharCount (line) < (MEMDB_MAX/sizeof(WCHAR))) {
  1334. g_CurrentLine = line;
  1335. StringCopy (ls.FullLine, line);
  1336. pSaveItem (&ls, DOSMIG_MIGRATE);
  1337. }
  1338. FreeText (line);
  1339. }
  1340. }
  1341. ELSE_DEBUGMSG ((DBG_VERBOSE, "Skipping excluded environment variable %s.", e.CurrentString));
  1342. } while (EnumNextMultiSz (&e));
  1343. //
  1344. // Add %windir% as an environment variable in NT. %windir% is implicit, but is not passed down to the
  1345. // WOW layer on NT.
  1346. //
  1347. line = AllocPathString (MAX_TCHAR_PATH);
  1348. wsprintf (line, TEXT("SET WINDIR=%s"), g_WinDir);
  1349. g_CurrentLine = line;
  1350. StringCopy (ls.FullLine, line);
  1351. pSaveItem (&ls, DOSMIG_MIGRATE);
  1352. FreePathString (line);
  1353. }
  1354. }
  1355. __finally {
  1356. if (envVars) {
  1357. FreeEnvironmentStrings(envVars);
  1358. }
  1359. HtFree (excludeTable);
  1360. }
  1361. return rSuccess;
  1362. }
  1363. LONG
  1364. pProcessDosConfigFiles (
  1365. void
  1366. )
  1367. {
  1368. BeginMessageProcessing();
  1369. g_DosMigPool = PoolMemInitNamedPool ("DosMig");
  1370. if (g_DosMigPool) {
  1371. if (!ParseDosFiles()) {
  1372. DEBUGMSG ((DBG_ERROR, "Errors occurred during the processing of DOS configuration files. Some dos settings may not be preserved."));
  1373. }
  1374. if (!ParseEnvironmentVariables()) {
  1375. DEBUGMSG ((DBG_ERROR, "Errors occured during the processing of environment variables. Environment variables may not be preserved."));
  1376. }
  1377. PoolMemDestroyPool(g_DosMigPool);
  1378. }
  1379. EndMessageProcessing();
  1380. return ERROR_SUCCESS;
  1381. }
  1382. DWORD
  1383. ProcessDosConfigFiles (
  1384. IN DWORD Request
  1385. )
  1386. {
  1387. switch (Request) {
  1388. case REQUEST_QUERYTICKS:
  1389. return TICKS_DOSMIG_PREPARE_REPORT;
  1390. case REQUEST_RUN:
  1391. return pProcessDosConfigFiles ();
  1392. default:
  1393. DEBUGMSG ((DBG_ERROR, "Bad parameter in DosMig_PrepareReport"));
  1394. }
  1395. return 0;
  1396. }
  1397. BOOL
  1398. DosMig_Entry (
  1399. IN HINSTANCE hinstDLL,
  1400. IN DWORD dwReason,
  1401. IN LPVOID lpv
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. This routine initializes the g_CfgFiles structure.
  1406. Arguments:
  1407. None.
  1408. Return Value:
  1409. Returns true if g_CfgFiles was successfully initialized,
  1410. FALSE otherwise.
  1411. --*/
  1412. {
  1413. BOOL rFlag = TRUE;
  1414. switch (dwReason)
  1415. {
  1416. case DLL_PROCESS_ATTACH:
  1417. break;
  1418. case DLL_PROCESS_DETACH:
  1419. break;
  1420. }
  1421. return rFlag;
  1422. }