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.

868 lines
28 KiB

  1. /* cmdmisc.c - Misc. SVC routines of Command.lib
  2. *
  3. *
  4. * Modification History:
  5. *
  6. * Sudeepb 17-Sep-1991 Created
  7. */
  8. #include "cmd.h"
  9. #include <cmdsvc.h>
  10. #include <demexp.h>
  11. #include <softpc.h>
  12. #include <mvdm.h>
  13. #include <ctype.h>
  14. #include <memory.h>
  15. #include "host_def.h"
  16. #include "oemuni.h"
  17. #include "nt_pif.h"
  18. #include "nt_uis.h" // For resource id
  19. #include "dpmtbls.h" // Dynamic Patch Module support
  20. #include "wowcmpat.h"
  21. VOID GetWowKernelCmdLine(VOID);
  22. extern ULONG fSeparateWow;
  23. #if defined(KOREA)
  24. //To fix HaNa spread sheet IME hot key problem
  25. //09/20/96 bklee. See mvdm\v86\monitor\i386\monitor.c
  26. BOOL bIgnoreExtraKbdDisable = FALSE;
  27. #endif
  28. extern PFAMILY_TABLE *pgDpmVdmFamTbls;
  29. VOID cmdGetNextCmd (VOID)
  30. {
  31. LPSTR lpszCmd;
  32. PCMDINFO pCMDInfo;
  33. ULONG cb;
  34. PREDIRCOMPLETE_INFO pRdrInfo;
  35. VDMINFO MyVDMInfo;
  36. char *pSrc, *pDst;
  37. char achCurDirectory[MAXIMUM_VDM_CURRENT_DIR + 4];
  38. char CmdLine[MAX_PATH];
  39. //
  40. // This routine is called once for WOW VDMs, to retrieve the
  41. // "krnl386" command line.
  42. // 5
  43. if (VDMForWOW) {
  44. GetWowKernelCmdLine();
  45. return;
  46. }
  47. VDMInfo.VDMState = 0;
  48. pCMDInfo = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
  49. VDMInfo.ErrorCode = FETCHWORD(pCMDInfo->ReturnCode);
  50. VDMInfo.CmdSize = sizeof(CmdLine);
  51. VDMInfo.CmdLine = CmdLine;
  52. VDMInfo.AppName = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->ExecPathSeg),
  53. FETCHWORD(pCMDInfo->ExecPathOff));
  54. VDMInfo.AppLen = FETCHWORD(pCMDInfo->ExecPathSize);
  55. VDMInfo.PifLen = 0;
  56. VDMInfo.EnviornmentSize = 0;
  57. VDMInfo.Enviornment = NULL;
  58. VDMInfo.CurDrive = 0;
  59. VDMInfo.TitleLen = 0;
  60. VDMInfo.ReservedLen = 0;
  61. VDMInfo.DesktopLen = 0;
  62. VDMInfo.CurDirectoryLen = MAX_PATH + 1;
  63. VDMInfo.CurDirectory = achCurDirectory;
  64. if(IsFirstCall){
  65. VDMInfo.VDMState = ASKING_FOR_FIRST_COMMAND;
  66. VDMInfo.ErrorCode = 0;
  67. DeleteConfigFiles(); // get rid of the temp boot files
  68. // When COMMAND.COM issues first cmdGetNextCmd, it has
  69. // a completed environment already(cmdGetInitEnvironment),
  70. // Therefore, we don't have to ask environment from BASE
  71. cmdVDMEnvBlk.lpszzEnv = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
  72. cmdVDMEnvBlk.cchEnv = FETCHWORD(pCMDInfo->EnvSize);
  73. // Check BLASTER environment variable to determine if Sound Blaster
  74. // emulation should be disabled.
  75. cb = cmdGetEnvironmentVariable(NULL, "BLASTER", CmdLine, MAX_PATH);
  76. if (cb !=0 && cb <= MAX_PATH) {
  77. SbReinitialize(CmdLine, MAX_PATH);
  78. }
  79. //clear bits that track printer flushing
  80. host_lpt_flush_initialize();
  81. // save ptr to global DPM tables for DOS
  82. pgDpmDosFamTbls = DPMFAMTBLS();
  83. InitGlobalDpmTables(pgDpmVdmFamTbls, NUM_VDM_FAMILIES_HOOKED);
  84. }
  85. else {
  86. // Get rid of all the SDB command line parameter stuff associated with
  87. // the app compat flags.
  88. if((cCmdLnParmStructs > 0) || dwDosCompatFlags) {
  89. // Get rid of the Dynamic Patch tables for this task.
  90. if(dwDosCompatFlags & WOWCF2_DPM_PATCHES) {
  91. FreeTaskDpmSupport(DPMFAMTBLS(),
  92. NUM_VDM_FAMILIES_HOOKED,
  93. pgDpmDosFamTbls);
  94. }
  95. FreeCmdLnParmStructs(pCmdLnParms, cCmdLnParmStructs);
  96. cCmdLnParmStructs = 0;
  97. dwDosCompatFlags = 0;
  98. }
  99. // program has terminated. If the termiation was issued from
  100. // second(or later) instance of command.com(cmd.exe), don't
  101. // reset the flag.
  102. if (Exe32ActiveCount == 0)
  103. DontCheckDosBinaryType = FALSE;
  104. // tell the base our new current directories (in ANSI)
  105. // we don't do it on repeat call(the shell out case is handled in
  106. // return exit code
  107. if (!IsRepeatCall) {
  108. cmdUpdateCurrentDirectories((BYTE)pCMDInfo->CurDrive);
  109. }
  110. VDMInfo.VDMState = 0;
  111. if(!IsRepeatCall){
  112. demCloseAllPSPRecords ();
  113. if (!pfdata.CloseOnExit && DosSessionId)
  114. nt_block_event_thread(1);
  115. else
  116. nt_block_event_thread(0);
  117. if (DosSessionId) {
  118. pRdrInfo = (PREDIRCOMPLETE_INFO) FETCHDWORD(pCMDInfo->pRdrInfo);
  119. if (!pfdata.CloseOnExit){
  120. char achTitle[MAX_PATH];
  121. char achInactive[60]; //should be plenty for 'inactive'
  122. strcpy (achTitle, "[");
  123. if (!LoadString(GetModuleHandle(NULL), EXIT_NO_CLOSE,
  124. achInactive, 60))
  125. strcat (achTitle, "Inactive ");
  126. else
  127. strcat(achTitle, achInactive);
  128. cb = strlen(achTitle);
  129. // GetConsoleTitleA and SetConsoleTitleA
  130. // are working on OEM character set.
  131. GetConsoleTitleA(achTitle + cb, MAX_PATH - cb - 1);
  132. cb = strlen(achTitle);
  133. achTitle[cb] = ']';
  134. achTitle[cb + 1] = '\0';
  135. SetConsoleTitleA(achTitle);
  136. // finish touch on redirection stuff
  137. cmdCheckCopyForRedirection (pRdrInfo, FALSE);
  138. Sleep(INFINITE);
  139. }
  140. else {
  141. // finish touch on redirection stuff
  142. // this will wait on the output thread if there
  143. // are any.
  144. cmdCheckCopyForRedirection (pRdrInfo, TRUE);
  145. VdmExitCode = VDMInfo.ErrorCode;
  146. TerminateVDM();
  147. }
  148. }
  149. fBlock = TRUE;
  150. }
  151. }
  152. if(IsRepeatCall) {
  153. VDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
  154. if( VDMInfo.ErrorCode != 0 )
  155. IsRepeatCall = FALSE;
  156. }
  157. VDMInfo.VDMState |= ASKING_FOR_DOS_BINARY;
  158. if (!IsFirstCall && !(VDMInfo.VDMState & ASKING_FOR_SECOND_TIME)) {
  159. pRdrInfo = (PREDIRCOMPLETE_INFO) FETCHDWORD(pCMDInfo->pRdrInfo);
  160. if (!cmdCheckCopyForRedirection (pRdrInfo, FALSE))
  161. VDMInfo.ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  162. }
  163. // Leave the current directory in a safe place, so that other 32bit
  164. // apps etc. can delnode this directory (and other such operations) later.
  165. if ( IsFirstCall == FALSE && IsRepeatCall == FALSE )
  166. SetCurrentDirectory (cmdHomeDirectory);
  167. // TSRExit will be set to 1, only if we are coming from command.com's
  168. // prompt and user typed an exit. We need to kill our parent also, so we
  169. // should write an exit in the console buffer.
  170. if (FETCHWORD(pCMDInfo->fTSRExit)) {
  171. cmdPushExitInConsoleBuffer ();
  172. }
  173. /**
  174. Merging environment is required if
  175. (1). Not the first comamnd &&
  176. (2). NTVDM is running on an existing console ||
  177. NTVDM has been shelled out.
  178. Note that WOW doesn't need enviornment merging.
  179. **/
  180. if (!DosEnvCreated && !IsFirstCall && (!DosSessionId || Exe32ActiveCount)) {
  181. RtlZeroMemory(&MyVDMInfo, sizeof(VDMINFO));
  182. MyVDMInfo.VDMState = ASKING_FOR_ENVIRONMENT | ASKING_FOR_DOS_BINARY;
  183. if (IsRepeatCall) {
  184. MyVDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
  185. MyVDMInfo.ErrorCode = 0;
  186. }
  187. else
  188. MyVDMInfo.ErrorCode = VDMInfo.ErrorCode;
  189. MyVDMInfo.Enviornment = lpszzVDMEnv32;
  190. MyVDMInfo.EnviornmentSize = (USHORT) cchVDMEnv32;
  191. if (!GetNextVDMCommand(&MyVDMInfo) && MyVDMInfo.EnviornmentSize > cchVDMEnv32) {
  192. MyVDMInfo.Enviornment = realloc(lpszzVDMEnv32, MyVDMInfo.EnviornmentSize);
  193. if (MyVDMInfo.Enviornment == NULL) {
  194. RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
  195. TerminateVDM();
  196. }
  197. lpszzVDMEnv32 = MyVDMInfo.Enviornment;
  198. cchVDMEnv32 = MyVDMInfo.EnviornmentSize;
  199. MyVDMInfo.VDMState = ASKING_FOR_DOS_BINARY | ASKING_FOR_ENVIRONMENT |
  200. ASKING_FOR_SECOND_TIME;
  201. MyVDMInfo.TitleLen =
  202. MyVDMInfo.DesktopLen =
  203. MyVDMInfo.ReservedLen =
  204. MyVDMInfo.CmdSize =
  205. MyVDMInfo.AppLen =
  206. MyVDMInfo.PifLen =
  207. MyVDMInfo.CurDirectoryLen = 0;
  208. MyVDMInfo.ErrorCode = 0;
  209. if (!GetNextVDMCommand(&MyVDMInfo)) {
  210. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  211. TerminateVDM();
  212. }
  213. }
  214. if (!cmdCreateVDMEnvironment(&cmdVDMEnvBlk)) {
  215. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  216. TerminateVDM();
  217. }
  218. DosEnvCreated = TRUE;
  219. VDMInfo.ErrorCode = 0;
  220. }
  221. if (cmdVDMEnvBlk.cchEnv > FETCHWORD(pCMDInfo->EnvSize)) {
  222. setAX((USHORT)cmdVDMEnvBlk.cchEnv);
  223. setCF(1);
  224. IsFirstCall = FALSE;
  225. IsRepeatCall = TRUE;
  226. return;
  227. }
  228. if (DosEnvCreated)
  229. VDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
  230. if(!GetNextVDMCommand(&VDMInfo)){
  231. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  232. TerminateVDM();
  233. }
  234. IsRepeatCall = FALSE;
  235. IsFirstCall = FALSE;
  236. if(fBlock){
  237. nt_resume_event_thread();
  238. fBlock = FALSE;
  239. }
  240. // Sync VDMs enviornment variables for current directories
  241. cmdSetDirectories (lpszzVDMEnv32, &VDMInfo);
  242. // tell DOS that this is a dos executable and no further checking is
  243. // necessary
  244. *pIsDosBinary = 1;
  245. // Check for PIF files. If a pif file is being executed extract the
  246. // executable name, command line, current directory and title from the pif
  247. // file and place the stuff appropriately in VDMInfo. Note, if pif file
  248. // is invalid, we dont do any thing to vdminfo. In such a case we
  249. // pass the pif as it is to scs to execute which we know will fail and
  250. // will come back to cmdGettNextCmd with proper error code.
  251. cmdCheckForPIF (&VDMInfo);
  252. //
  253. // if forcedos, then don't check binary type on int 21 exec process,
  254. // so that child spawns stay in dos land. Begining with NT 4.0 forcedos.exe
  255. // no longer uses pif files to force execution of a binary as a dos exe.
  256. // It now uses a bit in CreateProcess (dwCreationFlags).
  257. //
  258. DontCheckDosBinaryType = (VDMInfo.dwCreationFlags & CREATE_FORCEDOS) != 0;
  259. // convert exec path name to upper case. This is what command.com expect
  260. if(WOW32_strupr(VDMInfo.AppName) == NULL) {
  261. pSrc = VDMInfo.AppName;
  262. while( *pSrc)
  263. *pSrc++ = (char)toupper((int)*pSrc);
  264. }
  265. // figure out the extention type
  266. // at least one char for the base name plus
  267. // EXTENTION_STRING_LEN for the extention
  268. // plus the NULL char
  269. if (VDMInfo.AppLen > 1 + EXTENTION_STRING_LEN + 1) {
  270. pSrc = (PCHAR)VDMInfo.AppName + VDMInfo.AppLen - 5;
  271. if (!strncmp(pSrc, EXE_EXTENTION_STRING, EXTENTION_STRING_LEN))
  272. STOREWORD(pCMDInfo->ExecExtType, EXE_EXTENTION);
  273. else if (!strncmp(pSrc, COM_EXTENTION_STRING, EXTENTION_STRING_LEN))
  274. STOREWORD(pCMDInfo->ExecExtType, COM_EXTENTION);
  275. else if (!strncmp(pSrc, BAT_EXTENTION_STRING, EXTENTION_STRING_LEN))
  276. STOREWORD(pCMDInfo->ExecExtType, BAT_EXTENTION);
  277. else
  278. STOREWORD(pCMDInfo->ExecExtType, UNKNOWN_EXTENTION);
  279. }
  280. else
  281. STOREWORD(pCMDInfo->ExecExtType, UNKNOWN_EXTENTION);
  282. // tell command.com the length of the app full path name.
  283. STOREWORD(pCMDInfo->ExecPathSize, VDMInfo.AppLen);
  284. //
  285. // Prepare ccom's UCOMBUF
  286. //
  287. lpszCmd = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->CmdLineSeg),
  288. FETCHWORD(pCMDInfo->CmdLineOff));
  289. // Copy filepart of AppName excluding extension to ccom's buffer
  290. pSrc = strrchr(VDMInfo.AppName, '\\');
  291. #if defined(KOREA)
  292. // To fix HaNa spread sheet IME hotkey problem.
  293. {
  294. LPSTR pStrt, pEnd;
  295. char szModName[9];
  296. SHORT len;
  297. pStrt = pSrc;
  298. if (pStrt==NULL)
  299. pStrt = VDMInfo.AppName;
  300. else
  301. pStrt++;
  302. if ( (pEnd = strchr (pStrt, '.')) == NULL) {
  303. strncpy (szModName, pStrt, 9);
  304. szModName[8] = '\0';
  305. }
  306. else {
  307. len = (SHORT) (pEnd - pStrt);
  308. if (len<=8) {
  309. strncpy (szModName, pStrt, len);
  310. szModName[len] = '\0';
  311. }
  312. }
  313. bIgnoreExtraKbdDisable = !(strcmp("HANASP", szModName));
  314. }
  315. #endif
  316. if (!pSrc) {
  317. pSrc = VDMInfo.AppName;
  318. }
  319. else {
  320. pSrc++;
  321. }
  322. pDst = lpszCmd + 2;
  323. while (*pSrc && *pSrc != '.') {
  324. *pDst++ = *pSrc++;
  325. }
  326. cb = strlen(CmdLine);
  327. // cmd line must be terminated with "\0xd\0xa\0". This is either done
  328. // by BASE or cmdCheckForPif function(cmdpif.c).
  329. ASSERT((cb >= 2) && (0xd == CmdLine[cb - 2]) && (0xa == CmdLine[cb - 1]));
  330. // if cmd line is not blank, separate program base name and
  331. // cmd line with a SPACE. If it IS blank, do not insert any white chars
  332. // or we end up passing white chars to the applications as cmd line
  333. // and some applications just can not live with that.
  334. // We do not strip leading white characters in the passed command line
  335. // so the application sees the original data.
  336. if (cb > 2)
  337. *pDst++ = ' ';
  338. // append the command tail(at least, "\0xd\0xa")
  339. strncpy(pDst, CmdLine, cb + 1);
  340. // set the count
  341. // cb has the cmd line length including the terminated 0xd and 0xa
  342. // It does NOT count the terminated NULL char.
  343. ASSERT((cb + pDst - lpszCmd - 2) <= 127);
  344. // minus 2 because the real data in lpszCmd start from lpszCmd[2]
  345. lpszCmd[1] = (CHAR)(cb + pDst - lpszCmd - 2);
  346. if (DosEnvCreated) {
  347. VDMInfo.Enviornment = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
  348. RtlMoveMemory(VDMInfo.Enviornment,
  349. cmdVDMEnvBlk.lpszzEnv,
  350. cmdVDMEnvBlk.cchEnv
  351. );
  352. STOREWORD(pCMDInfo->EnvSize,cmdVDMEnvBlk.cchEnv);
  353. free(cmdVDMEnvBlk.lpszzEnv);
  354. DosEnvCreated = FALSE;
  355. }
  356. STOREWORD(pCMDInfo->fBatStatus,(USHORT)VDMInfo.fComingFromBat);
  357. STOREWORD(pCMDInfo->CurDrive,VDMInfo.CurDrive);
  358. STOREWORD(pCMDInfo->NumDrives,nDrives);
  359. VDMInfo.CodePage = (ULONG) cmdMapCodePage (VDMInfo.CodePage);
  360. STOREWORD(pCMDInfo->CodePage,(USHORT)VDMInfo.CodePage);
  361. cmdVDMEnvBlk.lpszzEnv = NULL;
  362. cmdVDMEnvBlk.cchEnv = 0;
  363. IsFirstVDM = FALSE;
  364. // Handle Standard IO redirection
  365. pRdrInfo = cmdCheckStandardHandles (&VDMInfo,&pCMDInfo->bStdHandles);
  366. STOREDWORD(pCMDInfo->pRdrInfo,(ULONG)pRdrInfo);
  367. // Tell DOS that it has to invalidate the CDSs
  368. *pSCS_ToSync = (CHAR)0xff;
  369. setCF(0);
  370. // Get the app comapt flags & associated command line parameters from the
  371. // app compat SDB for this app.
  372. pCmdLnParms = InitVdmSdbInfo((LPCSTR)VDMInfo.AppName,
  373. &dwDosCompatFlags,
  374. &cCmdLnParmStructs);
  375. return;
  376. }
  377. VOID GetWowKernelCmdLine(VOID)
  378. {
  379. CMDINFO UNALIGNED *pCMDInfo;
  380. PCHAR pch;
  381. CHAR szKrnl386[]="krnl386.exe";
  382. CHAR szPath[MAX_PATH+1];
  383. DeleteConfigFiles(); // get rid of the temp boot files
  384. host_lpt_flush_initialize();
  385. //
  386. // Only a few things need be set for WOW.
  387. // 1. NumDrives
  388. // 2. Kernel CmdLine (get from ntvdm command tail)
  389. // 3. Current drive
  390. //
  391. // Command.com has setup correct enviroment block at
  392. // this moment, so don't bother to mess with environment stuff.
  393. pCMDInfo = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
  394. pCMDInfo->NumDrives = nDrives;
  395. //
  396. // We used to get the info from a command line parameter, which
  397. // consisted of a fully qualified short path file name:
  398. // "-a %SystemRoot%\system32\krnl386.exe".
  399. //
  400. // We now remove that parameter and simply assume that for
  401. // wow we will use %SystemRoot%\system32\krnl386.exe
  402. //
  403. //
  404. // Make sure we have enough space for the two strings concatenated.
  405. // ulSystem32PathLen does not include the terminator, but
  406. // sizeof( szKrnl386 ) does, so we only need one more for the '\'.
  407. //
  408. if (ulSystem32PathLen + 1 + sizeof (szKrnl386) > FETCHWORD(pCMDInfo->ExecPathSize)) {
  409. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  410. TerminateVDM();
  411. }
  412. pch = (PCHAR)GetVDMAddr(FETCHWORD(pCMDInfo->ExecPathSeg),
  413. FETCHWORD(pCMDInfo->ExecPathOff));
  414. memcpy(pch, pszSystem32Path, ulSystem32PathLen);
  415. *(pch + ulSystem32PathLen) = '\\';
  416. memcpy(pch + ulSystem32PathLen + 1, szKrnl386, sizeof(szKrnl386));
  417. pCMDInfo->ExecPathSize = (WORD)(ulSystem32PathLen + 1 + sizeof(szKrnl386));
  418. pCMDInfo->ExecExtType = EXE_EXTENTION; // for WOW, use EXE extention
  419. //
  420. // Copy filepart of first token and rest to CmdLine buffer
  421. //
  422. pch = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->CmdLineSeg),
  423. FETCHWORD(pCMDInfo->CmdLineOff));
  424. if (FETCHWORD(pCMDInfo->CmdLineSize)<sizeof(szKrnl386)+2) {
  425. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  426. TerminateVDM();
  427. }
  428. memcpy(pch, szKrnl386, sizeof(szKrnl386)-1);
  429. memcpy(pch+sizeof(szKrnl386)-1, "\x0d\x0a\0", 3);
  430. *pIsDosBinary = 1;
  431. IsRepeatCall = FALSE;
  432. IsFirstCall = FALSE;
  433. // Tell DOS that it has to invalidate the CDSs
  434. *pSCS_ToSync = (CHAR)0xff;
  435. setCF(0);
  436. return;
  437. }
  438. /* cmdGetCurrentDir - Return the current directory for a drive.
  439. *
  440. *
  441. * Entry - Client (DS:SI) - buffer to return the directory
  442. * Client (AL) - drive being queried (0 = A)
  443. *
  444. * EXIT - SUCCESS Client (CY) clear
  445. * FAILURE Client (CY) set
  446. * (AX) = 0 (Directory was bigger than 64)
  447. * (AX) = 1 (the drive is not valid)
  448. *
  449. */
  450. VOID cmdGetCurrentDir (VOID)
  451. {
  452. PCHAR lpszCurDir;
  453. UCHAR chDrive;
  454. CHAR EnvVar[] = "=?:";
  455. CHAR RootName[] = "?:\\";
  456. DWORD EnvVarLen;
  457. UINT DriveType;
  458. lpszCurDir = (PCHAR) GetVDMAddr ((USHORT)getDS(),(USHORT)getSI());
  459. chDrive = getAL();
  460. EnvVar[1] = chDrive + 'A';
  461. RootName[0] = chDrive + 'A';
  462. // if the drive doesn't exist, blindly clear the environment var
  463. // and return error
  464. DriveType = demGetPhysicalDriveType(chDrive);
  465. if (DriveType == DRIVE_UNKNOWN) {
  466. DriveType = GetDriveTypeOem(RootName);
  467. }
  468. if (DriveType == DRIVE_UNKNOWN || DriveType == DRIVE_NO_ROOT_DIR){
  469. SetEnvironmentVariableOem(EnvVar, NULL);
  470. setCF(1);
  471. setAX(0);
  472. return;
  473. }
  474. if((EnvVarLen = GetEnvironmentVariableOem (EnvVar,lpszCurDir,
  475. MAXIMUM_VDM_CURRENT_DIR+3)) == 0){
  476. // if its not in env then and drive exist then we have'nt
  477. // yet touched it.
  478. strcpy(lpszCurDir, RootName);
  479. SetEnvironmentVariableOem (EnvVar,RootName);
  480. setCF(0);
  481. return;
  482. }
  483. if (EnvVarLen > MAXIMUM_VDM_CURRENT_DIR+3) {
  484. setCF(1);
  485. setAX(0);
  486. }
  487. else {
  488. setCF(0);
  489. }
  490. return;
  491. }
  492. /* cmdSetInfo - Set the address of SCS_ToSync variable in DOSDATA.
  493. * This variable is set whenever SCS dispatches a new
  494. * command to command.com. Setting of this variable
  495. * indicates to dos to validate all the CDS structures
  496. * for local drives.
  497. *
  498. *
  499. * Entry - Client (DS:DX) - pointer to SCSINFO
  500. * Client (DS:BX) - pointer to SCS_Is_Dos_Binary
  501. * Client (DS:CX) - pointer to SCS_FDACCESS
  502. *
  503. * EXIT - None
  504. */
  505. VOID cmdSetInfo (VOID)
  506. {
  507. pSCSInfo = (PSCSINFO) GetVDMAddr (getDS(),getDX());
  508. pSCS_ToSync = (PCHAR) &pSCSInfo->SCS_ToSync;
  509. pIsDosBinary = (BYTE *) GetVDMAddr(getDS(), getBX());
  510. pFDAccess = (WORD *) GetVDMAddr(getDS(), getCX());
  511. return;
  512. }
  513. VOID cmdSetDirectories (PCHAR lpszzEnv, VDMINFO * pVdmInfo)
  514. {
  515. LPSTR lpszVal;
  516. CHAR ch, chDrive, achEnvDrive[] = "=?:";
  517. ch = pVdmInfo->CurDrive + 'A';
  518. if (pVdmInfo->CurDirectoryLen != 0){
  519. SetCurrentDirectory(pVdmInfo->CurDirectory);
  520. achEnvDrive[1] = ch;
  521. SetEnvironmentVariable(achEnvDrive, pVdmInfo->CurDirectory);
  522. }
  523. if (lpszzEnv) {
  524. while(*lpszzEnv) {
  525. if(*lpszzEnv == '=' &&
  526. (chDrive = (CHAR)toupper(*(lpszzEnv+1))) >= 'A' &&
  527. chDrive <= 'Z' &&
  528. (*(PCHAR)((ULONG)lpszzEnv+2) == ':') &&
  529. chDrive != ch) {
  530. lpszVal = (PCHAR)((ULONG)lpszzEnv + 4);
  531. achEnvDrive[1] = chDrive;
  532. SetEnvironmentVariable (achEnvDrive,lpszVal);
  533. }
  534. lpszzEnv = strchr(lpszzEnv,'\0');
  535. lpszzEnv++;
  536. }
  537. }
  538. }
  539. static BOOL fConOutput = FALSE;
  540. VOID cmdComSpec (VOID)
  541. {
  542. LPSTR lpszCS;
  543. if(IsFirstCall == FALSE)
  544. return;
  545. lpszCS = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
  546. strcpy(lpszComSpec,"COMSPEC=");
  547. strcpy(lpszComSpec+8,lpszCS);
  548. cbComSpec = strlen(lpszComSpec) +1;
  549. setAL((BYTE)(!fConOutput || VDMForWOW));
  550. return;
  551. }
  552. /* cmdInitConsole - Let Video VDD know that it can start console output
  553. * operations.
  554. *
  555. *
  556. * Entry - None
  557. *
  558. *
  559. * EXIT - None
  560. *
  561. */
  562. VOID cmdInitConsole (VOID)
  563. {
  564. if (fConOutput == FALSE) {
  565. fConOutput = TRUE;
  566. nt_init_event_thread ();
  567. }
  568. return;
  569. }
  570. /* cmdMapCodePage - Map the Win32 Code page to DOS code page
  571. */
  572. USHORT cmdMapCodePage (ULONG CodePage)
  573. {
  574. // Currently We understand US code page only
  575. if (CodePage == 1252)
  576. return 437;
  577. else
  578. return ((USHORT)CodePage);
  579. }
  580. VOID cmdUpdateCurrentDirectories(BYTE CurDrive)
  581. {
  582. DWORD cchRemain, cchCurDir;
  583. CHAR *lpszCurDir;
  584. BYTE Drive;
  585. DWORD DriveType;
  586. CHAR achName[] = "=?:";
  587. CHAR RootName[] = "?:\\";
  588. // allocate new space for the new current directories
  589. lpszzCurrentDirectories = (CHAR*) malloc(MAX_PATH);
  590. cchCurrentDirectories = 0;
  591. cchRemain = MAX_PATH;
  592. lpszCurDir = lpszzCurrentDirectories;
  593. if (lpszCurDir != NULL) {
  594. Drive = 0;
  595. // current directory is the first entry
  596. achName[1] = CurDrive + 'A';
  597. cchCurrentDirectories = GetEnvironmentVariable(
  598. achName,
  599. lpszCurDir,
  600. cchRemain
  601. );
  602. if (cchCurrentDirectories == 0 || cchCurrentDirectories > MAX_PATH) {
  603. free(lpszzCurrentDirectories);
  604. lpszzCurrentDirectories = NULL;
  605. cchCurrentDirectories = 0;
  606. return;
  607. }
  608. cchRemain -= ++cchCurrentDirectories;
  609. // we got current directory already. Keep the drive number
  610. lpszCurDir += cchCurrentDirectories;
  611. while (Drive < 26) {
  612. // ignore invalid drives and current drive
  613. if (Drive != CurDrive) {
  614. DriveType = demGetPhysicalDriveType(Drive);
  615. if (DriveType == DRIVE_UNKNOWN) {
  616. RootName[0] = (CHAR)('A' + Drive);
  617. DriveType = GetDriveTypeOem(RootName);
  618. }
  619. if (DriveType != DRIVE_UNKNOWN &&
  620. DriveType != DRIVE_NO_ROOT_DIR )
  621. {
  622. achName[1] = Drive + 'A';
  623. cchCurDir = GetEnvironmentVariable(
  624. achName,
  625. lpszCurDir,
  626. cchRemain
  627. );
  628. if(cchCurDir > cchRemain) {
  629. lpszCurDir = (CHAR *)realloc(lpszzCurrentDirectories,
  630. cchRemain + MAX_PATH + cchCurrentDirectories
  631. );
  632. if (lpszCurDir == NULL) {
  633. free(lpszzCurrentDirectories);
  634. lpszzCurrentDirectories = NULL;
  635. cchCurrentDirectories = 0;
  636. return;
  637. }
  638. lpszzCurrentDirectories = lpszCurDir;
  639. lpszCurDir += cchCurrentDirectories;
  640. cchRemain += MAX_PATH;
  641. cchCurDir = GetEnvironmentVariable(
  642. achName,
  643. lpszCurDir,
  644. cchRemain
  645. );
  646. }
  647. if (cchCurDir != 0) {
  648. // GetEnvironmentVariable doesn't count the NULL char
  649. lpszCurDir += ++cchCurDir;
  650. cchRemain -= cchCurDir;
  651. cchCurrentDirectories += cchCurDir;
  652. }
  653. }
  654. }
  655. // next drive
  656. Drive++;
  657. }
  658. lpszCurDir = lpszzCurrentDirectories;
  659. // need space for the ending NULL and shrink the space if necessary
  660. lpszzCurrentDirectories = (CHAR *) realloc(lpszCurDir, cchCurrentDirectories + 1);
  661. if (lpszzCurrentDirectories != NULL && cchCurrentDirectories != 0){
  662. lpszzCurrentDirectories[cchCurrentDirectories++] = '\0';
  663. SetVDMCurrentDirectories(cchCurrentDirectories, lpszzCurrentDirectories);
  664. free(lpszzCurrentDirectories);
  665. lpszzCurrentDirectories = NULL;
  666. cchCurrentDirectories = 0;
  667. }
  668. else {
  669. free(lpszCurDir);
  670. cchCurrentDirectories = 0;
  671. }
  672. }
  673. }
  674. /* This SVC function tells command.com, if the VDM was started without an
  675. * existing console. If so, on finding a TSR, command.com will return
  676. * back to GetNextVDMCommand, rather than putting its own popup.
  677. *
  678. * Entry - None
  679. *
  680. * Exit - Client (AL) = 0 if started with an existing console
  681. * Client (AL) = 1 if started with new console
  682. */
  683. VOID cmdGetStartInfo (VOID)
  684. {
  685. setAL((BYTE) (DosSessionId ? 1 : 0));
  686. return;
  687. }
  688. #ifdef DBCS // this should go to US build also
  689. /* This SVC function changes the window title. This function get called
  690. * from command.com when TSRs are installed and scs_cmdprompt is off
  691. * (command.com does its prompt).
  692. *
  693. * Entry - Client (AL) = 0, restore bare title
  694. * Client (AL) != 1, set new program title,
  695. * DS:SI point to a CRLF terminated program name
  696. *
  697. * Exit - none
  698. *
  699. */
  700. VOID cmdSetWinTitle(VOID)
  701. {
  702. static CHAR achCommandPrompt[64] = {'\0'};
  703. CHAR achBuf[256], *pch, *pch1;
  704. if (achCommandPrompt[0] == '\0') {
  705. if (!LoadString(GetModuleHandle(NULL),
  706. IDS_PROMPT,
  707. achCommandPrompt,
  708. 64
  709. ))
  710. strcpy(achCommandPrompt, "Command Prompt");
  711. }
  712. if (getAL() == 0)
  713. SetConsoleTitleA(achCommandPrompt);
  714. else {
  715. pch = (CHAR *)GetVDMAddr(getDS(), getSI());
  716. pch1 = strchr(pch, 0x0d);
  717. if (pch1 == NULL)
  718. SetConsoleTitleA(achCommandPrompt);
  719. else {
  720. *pch1 = '\0';
  721. strcpy(achBuf, achCommandPrompt);
  722. strcat(achBuf, " - ");
  723. strncat(achBuf, pch,sizeof(achBuf) - strlen(achBuf));
  724. achBuf[sizeof(achBuf)-1] = 0;
  725. *pch1 = 0x0d;
  726. SetConsoleTitleA(achBuf);
  727. }
  728. }
  729. }
  730. #endif // DBCS