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.

516 lines
12 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. vdm.c
  5. Abstract:
  6. Routines to configure the MS-DOS subsystem.
  7. Author:
  8. Ted Miller (tedm) 27-Apr-1995
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #pragma hdrstop
  13. //
  14. // Keywords whose presence in config.sys indicate OS/2.
  15. //
  16. PCSTR Os2ConfigSysKeywords[] = { "DISKCACHE", "LIBPATH", "PAUSEONERROR",
  17. "RMSIZE", "RUN", "SWAPPATH",
  18. "IOPL", "MAXWAIT", "MEMMAN",
  19. "PRIORITY", "PROTSHELL", "PROTECTONLY",
  20. "THREADS", "TIMESLICE", "TRACE",
  21. "TRACEBUF", "DEVINFO", NULL
  22. };
  23. //
  24. // Keywords we migrate from the user's existing DOS config.sys
  25. // into config.nt.
  26. //
  27. #define NUM_DOS_KEYWORDS 4
  28. PCSTR DosConfigSysKeywords[NUM_DOS_KEYWORDS] = { "FCBS","BREAK","LASTDRIVE","FILES" };
  29. BOOL
  30. DosConfigSysExists(
  31. IN PCWSTR Filename
  32. );
  33. BOOL
  34. CreateConfigNt(
  35. IN PCWSTR ConfigDos,
  36. IN PCWSTR ConfigTmp,
  37. IN PCWSTR ConfigNt
  38. );
  39. PSTR
  40. IsolateFirstField(
  41. IN PSTR Line,
  42. OUT PSTR *End,
  43. OUT PCHAR Terminator
  44. );
  45. BOOL
  46. ConfigureMsDosSubsystem(
  47. VOID
  48. )
  49. /*++
  50. Routine Description:
  51. Configure the 16-bit MS-DOS subsystem.
  52. Currently this means creating config.nt and autoexec.nt.
  53. It also means creating empty config.sys, autoexec.bat, io.sys and msdos.sys
  54. if these files don't already exist.
  55. On the upgrade, the only thing that we do is to create the empty files,
  56. if they don't already exist.
  57. Arguments:
  58. None.
  59. Return Value:
  60. Boolean value indicating outcome.
  61. --*/
  62. {
  63. WCHAR ConfigDos[] = L"?:\\CONFIG.SYS";
  64. WCHAR ConfigTmp[MAX_PATH];
  65. WCHAR ConfigNt[MAX_PATH];
  66. WCHAR AutoexecDos[] = L"?:\\AUTOEXEC.BAT";
  67. WCHAR AutoexecTmp[MAX_PATH];
  68. WCHAR AutoexecNt[MAX_PATH];
  69. WCHAR IoSysFile[] = L"?:\\IO.SYS";
  70. WCHAR MsDosSysFile[] = L"?:\\MSDOS.SYS";
  71. WCHAR ControlIniFile[MAX_PATH];
  72. BOOL b;
  73. DWORD Result;
  74. ULONG i;
  75. HANDLE FileHandle;
  76. PWSTR DosFileNames[] = {
  77. ConfigDos,
  78. AutoexecDos,
  79. IoSysFile,
  80. MsDosSysFile,
  81. ControlIniFile
  82. };
  83. DWORD DosFileAttributes[] = {
  84. FILE_ATTRIBUTE_NORMAL,
  85. FILE_ATTRIBUTE_NORMAL,
  86. FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY,
  87. FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY,
  88. FILE_ATTRIBUTE_NORMAL
  89. };
  90. //
  91. // Fill in drive letter of system partition.
  92. //
  93. #ifdef _X86_
  94. ConfigDos[0] = x86SystemPartitionDrive;
  95. AutoexecDos[0] = x86SystemPartitionDrive;
  96. IoSysFile[0] = x86SystemPartitionDrive;
  97. MsDosSysFile[0] = x86SystemPartitionDrive;
  98. #else
  99. ConfigDos[0] = L'C';
  100. AutoexecDos[0] = L'C';
  101. IoSysFile[0] = L'C';
  102. MsDosSysFile[0] = L'C';
  103. #endif
  104. //
  105. // Build path to control.ini file
  106. //
  107. Result = GetWindowsDirectory(ControlIniFile,MAX_PATH);
  108. if( Result == 0) {
  109. MYASSERT(FALSE);
  110. return FALSE;
  111. }
  112. pSetupConcatenatePaths(ControlIniFile,L"control.ini",MAX_PATH,NULL);
  113. //
  114. // Create empty config.sys, autoexec.bat, io.sys, msdos.sys and control.ini
  115. // if they don't exist. This is because some 16-bit apps depend on
  116. // these files and SudeepB wants this moved from VDM to setup.
  117. //
  118. for( i = 0; i < sizeof( DosFileNames ) / sizeof( PWSTR ); i++ ) {
  119. FileHandle = CreateFile( DosFileNames[i],
  120. GENERIC_READ | GENERIC_WRITE,
  121. 0, // File is not to be shared
  122. NULL, // No security attributes
  123. CREATE_NEW, // Create only if it doesn't exist
  124. DosFileAttributes[i],
  125. NULL ); // No extended attributes
  126. if( FileHandle != INVALID_HANDLE_VALUE ) {
  127. CloseHandle( FileHandle );
  128. }
  129. }
  130. if( Upgrade ) {
  131. return( TRUE );
  132. }
  133. //
  134. // Form filenames.
  135. //
  136. GetSystemDirectory(ConfigTmp,MAX_PATH);
  137. lstrcpy(ConfigNt,ConfigTmp);
  138. lstrcpy(AutoexecNt,ConfigTmp);
  139. lstrcpy(AutoexecTmp,ConfigTmp);
  140. pSetupConcatenatePaths(ConfigTmp,L"CONFIG.TMP",MAX_PATH,NULL);
  141. pSetupConcatenatePaths(ConfigNt,L"CONFIG.NT",MAX_PATH,NULL);
  142. pSetupConcatenatePaths(AutoexecTmp,L"AUTOEXEC.TMP",MAX_PATH,NULL);
  143. pSetupConcatenatePaths(AutoexecNt,L"AUTOEXEC.NT",MAX_PATH,NULL);
  144. //
  145. // If the temp files don't exist, we're done.
  146. // If they do, set their attributes so that we can delete them later.
  147. //
  148. if(!FileExists(ConfigTmp,NULL) || !FileExists(AutoexecTmp,NULL)) {
  149. return(TRUE);
  150. }
  151. SetFileAttributes(ConfigTmp,FILE_ATTRIBUTE_NORMAL);
  152. SetFileAttributes(AutoexecTmp,FILE_ATTRIBUTE_NORMAL);
  153. //
  154. // Get rid of any existing nt config files. We don't support
  155. // merging/upgrading them; we support only ooverwriting them.
  156. //
  157. SetFileAttributes(ConfigNt,FILE_ATTRIBUTE_NORMAL);
  158. SetFileAttributes(AutoexecNt,FILE_ATTRIBUTE_NORMAL);
  159. DeleteFile(ConfigNt);
  160. DeleteFile(AutoexecNt);
  161. //
  162. // If a DOS config.sys exists, merge the template config.sys
  163. // and the dos config.sys to form the nt config.sys.
  164. // Otherwise move the config.sys template over to be the
  165. // nt config file.
  166. //
  167. if(DosConfigSysExists(ConfigDos)) {
  168. b = CreateConfigNt(ConfigDos,ConfigTmp,ConfigNt);
  169. } else {
  170. b = MoveFile(ConfigTmp,ConfigNt);
  171. }
  172. //
  173. // We don't do anything special with autoexec.bat.
  174. // Just move the template over to be the nt file.
  175. //
  176. if(!MoveFile(AutoexecTmp,AutoexecNt)) {
  177. b = FALSE;
  178. }
  179. return(b);
  180. }
  181. BOOL
  182. DosConfigSysExists(
  183. IN PCWSTR Filename
  184. )
  185. /*++
  186. Routine Description:
  187. Determine whether a given file is a DOS config.sys.
  188. Arguments:
  189. Filename - supplies name of file to check.
  190. Return Value:
  191. TRUE if the file exists and is not an OS/2 config.sys.
  192. FALSE if the file does not exist or is an OS/2 config.sys.
  193. --*/
  194. {
  195. BOOL b;
  196. FILE *f;
  197. CHAR Line[512];
  198. UINT i;
  199. PCHAR p;
  200. CHAR c;
  201. PSTR End;
  202. PSTR filename;
  203. filename = pSetupUnicodeToAnsi(Filename);
  204. if(!filename) {
  205. return(FALSE);
  206. }
  207. b = FALSE;
  208. if(FileExists(Filename,NULL)) {
  209. b = TRUE;
  210. if(f = fopen(filename,"rt")) {
  211. while(b && fgets(Line,sizeof(Line),f)) {
  212. if(p = IsolateFirstField(Line,&End,&c)) {
  213. for(i=0; b && Os2ConfigSysKeywords[i]; i++) {
  214. if(!lstrcmpiA(p,Os2ConfigSysKeywords[i])) {
  215. b = FALSE;
  216. }
  217. }
  218. }
  219. }
  220. fclose(f);
  221. }
  222. }
  223. MyFree(filename);
  224. return(b);
  225. }
  226. BOOL
  227. CreateConfigNt(
  228. IN PCWSTR ConfigDos,
  229. IN PCWSTR ConfigTmp,
  230. IN PCWSTR ConfigNt
  231. )
  232. /*++
  233. Routine Description:
  234. Create config.nt. This is done by merging config.tmp (copied during setup)
  235. and the user's existing DOS config.sys. We migrate certain lines from
  236. the DOS config.sys into config.nt.
  237. Arguments:
  238. ConfigDos - supplies filename of DOS config.sys.
  239. ConfigTmp - supplies filename of template config.sys.
  240. ConfigNt - supplies filename of config.nt to be created.
  241. Return Value:
  242. Boolean value indicating outcome.
  243. --*/
  244. {
  245. FILE *DosFile;
  246. FILE *NtFile;
  247. FILE *TmpFile;
  248. BOOL b;
  249. CHAR Line[512];
  250. PCHAR p;
  251. BOOL Found;
  252. BOOL SawKeyword[NUM_DOS_KEYWORDS];
  253. PCSTR FoundKeyword[NUM_DOS_KEYWORDS];
  254. PSTR FoundLine[NUM_DOS_KEYWORDS];
  255. UINT KeywordsFound;
  256. CHAR c;
  257. PSTR End;
  258. PCSTR configDos,configTmp,configNt;
  259. UINT i;
  260. //
  261. // Open the dos file for reading.
  262. // Create the nt file for writing.
  263. // Open the template file for reading.
  264. //
  265. b = FALSE;
  266. if(configDos = pSetupUnicodeToAnsi(ConfigDos)) {
  267. DosFile = fopen(configDos,"rt");
  268. MyFree(configDos);
  269. if(!DosFile) {
  270. goto err0;
  271. }
  272. } else {
  273. goto err0;
  274. }
  275. if(configNt = pSetupUnicodeToAnsi(ConfigNt)) {
  276. NtFile = fopen(configNt,"wt");
  277. MyFree(configNt);
  278. if(!NtFile) {
  279. goto err1;
  280. }
  281. } else {
  282. goto err1;
  283. }
  284. if(configTmp = pSetupUnicodeToAnsi(ConfigTmp)) {
  285. TmpFile = fopen(configTmp,"rt");
  286. MyFree(configTmp);
  287. if(!TmpFile) {
  288. goto err2;
  289. }
  290. } else {
  291. goto err2;
  292. }
  293. //
  294. // Process the DOS file. Read each line and see if it's one
  295. // we care about. If so, save it for later.
  296. //
  297. ZeroMemory(SawKeyword,sizeof(SawKeyword));
  298. KeywordsFound = 0;
  299. while(fgets(Line,sizeof(Line),DosFile)) {
  300. //
  301. // Isolate the first field.
  302. //
  303. if(p = IsolateFirstField(Line,&End,&c)) {
  304. //
  305. // See if we care about this line.
  306. //
  307. for(i=0; i<NUM_DOS_KEYWORDS; i++) {
  308. if(!SawKeyword[i] && !lstrcmpiA(p,DosConfigSysKeywords[i])) {
  309. //
  310. // Remember that we saw this line and save away
  311. // the rest of the line for later.
  312. //
  313. *End = c;
  314. SawKeyword[i] = TRUE;
  315. FoundKeyword[KeywordsFound] = DosConfigSysKeywords[i];
  316. FoundLine[KeywordsFound] = MyMalloc(lstrlenA(p)+1);
  317. if(!FoundLine[KeywordsFound]) {
  318. goto err3;
  319. }
  320. lstrcpyA(FoundLine[KeywordsFound],p);
  321. KeywordsFound++;
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. //
  328. // Look at each line in the template file.
  329. // If it's a line with a value we respect, make sure the line
  330. // does not exist in the DOS file. If it exists in the DOS file
  331. // use the DOS value instead.
  332. //
  333. while(fgets(Line,sizeof(Line),TmpFile)) {
  334. //
  335. // Isolate the first field in the template line and
  336. // check against those we found in the DOS file.
  337. //
  338. Found = FALSE;
  339. if(p = IsolateFirstField(Line,&End,&c)) {
  340. for(i=0; i<KeywordsFound; i++) {
  341. if(!lstrcmpiA(FoundKeyword[i],p)) {
  342. Found = TRUE;
  343. break;
  344. }
  345. }
  346. }
  347. *End = c;
  348. if(Found) {
  349. //
  350. // Use value we found in the dos file.
  351. //
  352. fputs(FoundLine[i],NtFile);
  353. } else {
  354. //
  355. // Use line from template file as-is.
  356. //
  357. fputs(Line,NtFile);
  358. }
  359. }
  360. b = TRUE;
  361. err3:
  362. for(i=0; i<KeywordsFound; i++) {
  363. MyFree(FoundLine[i]);
  364. }
  365. fclose(TmpFile);
  366. err2:
  367. fclose(NtFile);
  368. err1:
  369. fclose(DosFile);
  370. err0:
  371. return(b);
  372. }
  373. PSTR
  374. IsolateFirstField(
  375. IN PSTR Line,
  376. OUT PSTR *End,
  377. OUT PCHAR Terminator
  378. )
  379. /*++
  380. Routine Description:
  381. Isolate the first token in a line of config.sys. The first field
  382. starts at the first non-space/tab character, and is terminated
  383. by a space/tab, newline, or equals.
  384. Arguments:
  385. Line - supplies pointer to line whose first field is desired.
  386. End - receives a pointer to the character that termianted the first
  387. field. That character will have been overwritten with a nul byte.
  388. Terminator - receives the character that terminated the first field,
  389. before we overwrote it with a nul byte.
  390. Return Value:
  391. Pointer to the first field. If the line is blank, the return value
  392. will be NULL.
  393. --*/
  394. {
  395. PSTR p,q;
  396. //
  397. // Get start of first field.
  398. //
  399. p = Line;
  400. while((*p == ' ') || (*p == '\t')) {
  401. p++;
  402. }
  403. //
  404. // If line is empty or bogus, we're done.
  405. //
  406. if((*p == 0) || (*p == '\r') || (*p == '\n') || (*p == '=')) {
  407. return(NULL);
  408. }
  409. //
  410. // Find end of field.
  411. //
  412. q = p;
  413. while(*q && !strchr("\r\n \t=",*q)) {
  414. q++;
  415. }
  416. *End = q;
  417. *Terminator = *q;
  418. *q = 0;
  419. return(p);
  420. }