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.

1236 lines
33 KiB

  1. /* wdos.c - DOS realted functions for WOW
  2. *
  3. * Modification History
  4. *
  5. * Sudeepb 23-Aug-1991 Created
  6. */
  7. #include "precomp.h"
  8. #pragma hdrstop
  9. #include "curdir.h"
  10. MODNAME(wdos.c);
  11. ULONG demClientErrorEx (HANDLE hFile, CHAR chDrive, BOOL bSetRegs);
  12. extern DOSWOWDATA DosWowData;
  13. extern PWORD16 pCurTDB, pCurDirOwner;
  14. //
  15. // This is our local array of current directory strings. A particular entry
  16. // is only used if the directory becomes longer than the old MS-DOS limit
  17. // of 67 characters.
  18. //
  19. #define MAX_DOS_DRIVES 26
  20. LPSTR CurDirs[MAX_DOS_DRIVES] = {NULL};
  21. VOID DosWowUpdateTDBDir(UCHAR Drive, LPSTR pszDir);
  22. VOID DosWowUpdateCDSDir(UCHAR Drive, LPSTR pszDir);
  23. #ifdef DEBUG
  24. VOID __cdecl Dumpdir(LPSTR pszfn, LPSTR pszDir, ...);
  25. #else
  26. #define Dumpdir //
  27. #endif
  28. //
  29. // modify this to change all the current directory spew's logging level
  30. //
  31. #define CURDIR_LOGLEVEL 4
  32. /* First, a brief explanation on Windows and current directory
  33. *
  34. * 1. Windows keeps a single current directory (and drive off course) per
  35. * application. All the "other" drives are shared between the apps and
  36. * current dirs on them could change without further notice, such that
  37. * if app "Abra" has c as it's current drive and "c:\foo" is it's current
  38. * dir, and another app "Cadabra" has d as it's current drive and "d:\bar"
  39. * as it's current dir, then this is what apps get in return to the respective
  40. * system calls:
  41. * App Call Param result
  42. * Cadabra GetCurrentDirectory c: c:\foo
  43. * Abra SetCurrentDirectory c:\foobar
  44. * Cadabra GetCurrentDirectory c: c:\foobar
  45. * Abra SetCurrentDirectory d:\test
  46. * Abra GetCurrentDirectory d: d:\test
  47. * Cadabra GetCurrentDirectory d: d:\bar <- d is it's current drive!
  48. *
  49. * 2. Windows is a "non-preemptive" multitasking OS. Remember that for later.
  50. *
  51. * 3. Tasks are id'd by their respective TDB's which have these interesting
  52. * members (see tdb16.h for the complete list):
  53. *
  54. * TDB_Drive
  55. * TDB_LFNDirectory
  56. *
  57. * when the high bit of the TDB_Drive is set (TDB_DIR_VALID) -- TDB_LFNDirectory
  58. * is a valid current directory for the TDB_Drive (which is app's current
  59. * drive). The drive itself (0-based drive number) is stored in
  60. * TDB_Drive & ~TDB_DIR_VALID
  61. *
  62. * 4. Who touches TDB_Drive ?
  63. * SaveState code -- which is called when the task is being switched away *from*
  64. * it looks to see if info on current drive and directory in TDB is stale (via
  65. * the TDB_DIR_VALID bit) and calls GetDefaultDrive and GetCurrentDirectory to
  66. * make sure what's in TDB is valid
  67. *
  68. * 5. Task switching
  69. * When task resumes it's running due to explanation above -- it has valid
  70. * TDB_Drive in it. When the very first call to the relevant i21 is being
  71. * made -- kernel looks at the owner of the current drive (kernel variable)
  72. * and if some other task owns the current drive/directory -- it makes calls
  73. * to wow to set current drive/dir from the TDB (which is sure valid at
  74. * this point). Current Drive owner is set to the current task so that
  75. * the next time around this call is not performed -- and since windows does
  76. * not allow task preemptions -- any calls to set drive/directory are not
  77. * reflected upon tdb up until the task switch time.
  78. *
  79. * 6. WOW considerations
  80. * We in WOW have a great deal of hassle due to a number of APIs that are
  81. * not called from i21 handler but rather deal with file i/o and other
  82. * issues that depend upon Win32 current directory. Lo and behold we have
  83. * an UpdateDosCurrentDirectory call that we make before and after the call
  84. * to certain Win32 apis (which were found by trial and error)
  85. * The logic inside is that we always try to keep as much sync as possible
  86. * between TDB, CDS and Win32.
  87. *
  88. * 7. CurDirs
  89. * CDS can only accomodate current dirs which are up to 64 chars in length
  90. * hence there is an array of CurDirs which is filled on a per-need basis
  91. * for those drives that have curdir lengths > 64+3 chars
  92. *
  93. * 8. Belief
  94. * I profoundly believe that the above information is sufficient by large
  95. * to successfully troubleshoot all the "current directory" issues that may
  96. * arise :-)
  97. *
  98. * 9. Thanks
  99. * Goes to Neil and Dave for all the insight and patience that made all these
  100. * wonderful discoveries possible.
  101. *
  102. * -- VadimB, This day -- July, the 28th 1997
  103. */
  104. /* GetCurrentDir - Updatess current dir in CDS structure
  105. *
  106. * Entry - pcds = pointer to CDS
  107. * chDrive = Physical Drive in question (0, 1 ...)
  108. *
  109. * Exit
  110. * SUCCESS - returns TRUE
  111. *
  112. * FAILURE - returns FALSE
  113. */
  114. BOOL GetCurrentDir (PCDS pcds, UCHAR Drive)
  115. {
  116. static CHAR EnvVar[] = "=?:";
  117. DWORD EnvVarLen;
  118. BOOL bStatus = TRUE;
  119. UCHAR FixedCount;
  120. int i;
  121. PCDS pcdstemp;
  122. FixedCount = *(PUCHAR) DosWowData.lpCDSCount;
  123. //
  124. // from Macro.Asm in DOS:
  125. // ; Sudeepb 20-Dec-1991 ; Added for redirected drives
  126. // ; We always sync the redirected drives. Local drives are sync
  127. // ; as per the curdir_tosync flag and SCS_ToSync
  128. //
  129. if (*(PUCHAR)DosWowData.lpSCS_ToSync) {
  130. #ifdef FE_SB
  131. if (GetSystemDefaultLangID() == MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)) {
  132. PCDS_JPN pcdstemp_jpn;
  133. pcdstemp_jpn = (PCDS_JPN) DosWowData.lpCDSFixedTable;
  134. for (i=0;i < (int)FixedCount; i++, pcdstemp_jpn++)
  135. pcdstemp_jpn->CurDirJPN_Flags |= CURDIR_TOSYNC;
  136. }
  137. else {
  138. pcdstemp = (PCDS) DosWowData.lpCDSFixedTable;
  139. for (i=0;i < (int)FixedCount; i++, pcdstemp++)
  140. pcdstemp->CurDir_Flags |= CURDIR_TOSYNC;
  141. }
  142. #else
  143. pcdstemp = (PCDS) DosWowData.lpCDSFixedTable;
  144. for (i=0;i < (int)FixedCount; i++, pcdstemp++)
  145. pcdstemp->CurDir_Flags |= CURDIR_TOSYNC;
  146. #endif
  147. // Mark tosync in network drive as well
  148. pcdstemp = (PCDS)DosWowData.lpCDSBuffer;
  149. pcdstemp->CurDir_Flags |= CURDIR_TOSYNC;
  150. *(PUCHAR)DosWowData.lpSCS_ToSync = 0;
  151. }
  152. // If CDS needs to be synched or if the requested drive is different
  153. // then the the drive being used by NetCDS go refresh the CDS.
  154. if ((pcds->CurDir_Flags & CURDIR_TOSYNC) ||
  155. ((Drive >= FixedCount) && (pcds->CurDir_Text[0] != (Drive + 'A') &&
  156. pcds->CurDir_Text[0] != (Drive + 'a')))) {
  157. // validate media
  158. EnvVar[1] = Drive + 'A';
  159. if((EnvVarLen = GetEnvironmentVariableOem (EnvVar, (LPSTR)pcds,
  160. MAXIMUM_VDM_CURRENT_DIR+3)) == 0){
  161. // if its not in env then and drive exist then we have'nt
  162. // yet touched it.
  163. pcds->CurDir_Text[0] = EnvVar[1];
  164. pcds->CurDir_Text[1] = ':';
  165. pcds->CurDir_Text[2] = '\\';
  166. pcds->CurDir_Text[3] = 0;
  167. SetEnvironmentVariableOem ((LPSTR)EnvVar,(LPSTR)pcds);
  168. }
  169. if (EnvVarLen > MAXIMUM_VDM_CURRENT_DIR+3) {
  170. //
  171. // The current directory on this drive is too long to fit in the
  172. // cds. That's ok for a win16 app in general, since it won't be
  173. // using the cds in this case. But just to be more robust, put
  174. // a valid directory in the cds instead of just truncating it on
  175. // the off chance that it gets used.
  176. //
  177. pcds->CurDir_Text[0] = EnvVar[1];
  178. pcds->CurDir_Text[1] = ':';
  179. pcds->CurDir_Text[2] = '\\';
  180. pcds->CurDir_Text[3] = 0;
  181. }
  182. pcds->CurDir_Flags &= 0xFFFF - CURDIR_TOSYNC;
  183. pcds->CurDir_End = 2;
  184. }
  185. if (!bStatus) {
  186. *(PUCHAR)DosWowData.lpDrvErr = ERROR_INVALID_DRIVE;
  187. }
  188. return (bStatus);
  189. }
  190. /* SetCurrentDir - Set the current directory
  191. *
  192. *
  193. * Entry - lpBuf = pointer to string specifying new directory
  194. * chDrive = Physical Drive in question (0, 1 ...)
  195. *
  196. * Exit
  197. * SUCCESS returns TRUE
  198. * FAILURE returns FALSE
  199. *
  200. */
  201. BOOL SetCurrentDir (LPSTR lpBuf, UCHAR Drive)
  202. {
  203. static CHAR EnvVar[] = "=?:";
  204. CHAR chDrive = Drive + 'A';
  205. BOOL bRet;
  206. // ok -- we are setting the current directory ONLY if the drive
  207. // is the current drive for the app
  208. if (*(PUCHAR)DosWowData.lpCurDrv == Drive) { // if on the current drive--go win32
  209. bRet = SetCurrentDirectoryOem(lpBuf);
  210. }
  211. else { // verify it's a valid dir
  212. DWORD dwAttributes;
  213. dwAttributes = GetFileAttributesOem(lpBuf);
  214. bRet = (0xffffffff != dwAttributes) && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY);
  215. }
  216. if (!bRet) {
  217. demClientErrorEx(INVALID_HANDLE_VALUE, chDrive, FALSE);
  218. return(FALSE);
  219. }
  220. EnvVar[1] = chDrive;
  221. bRet = SetEnvironmentVariableOem((LPSTR)EnvVar,lpBuf);
  222. return (bRet);
  223. }
  224. /* QueryCurrentDir - Verifies current dir provided in CDS structure
  225. * for $CURRENT_DIR
  226. *
  227. * First Validates Media, if invalid -> i24 error
  228. * Next Validates Path, if invalid set path to root (not an error)
  229. *
  230. * Entry - Client (DS:SI) Buffer to CDS path to verify
  231. * Client (AL) Physical Drive in question (A=0, B=1, ...)
  232. *
  233. * Exit
  234. * SUCCESS
  235. * Client (CY) = 0
  236. *
  237. * FAILURE
  238. * Client (CY) = 1 , I24 drive invalid
  239. */
  240. BOOL QueryCurrentDir (PCDS pcds, UCHAR Drive)
  241. {
  242. DWORD dw;
  243. CHAR chDrive;
  244. static CHAR pPath[]="?:\\";
  245. static CHAR EnvVar[] = "=?:";
  246. // validate media
  247. chDrive = Drive + 'A';
  248. pPath[0] = chDrive;
  249. dw = GetFileAttributesOem(pPath);
  250. if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY))
  251. {
  252. demClientErrorEx(INVALID_HANDLE_VALUE, chDrive, FALSE);
  253. return (FALSE);
  254. }
  255. // if invalid path, set path to the root
  256. // reset CDS, and win32 env for win32
  257. dw = GetFileAttributesOem(pcds->CurDir_Text);
  258. if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY))
  259. {
  260. strcpy(pcds->CurDir_Text, pPath);
  261. pcds->CurDir_End = 2;
  262. EnvVar[1] = chDrive;
  263. SetEnvironmentVariableOem(EnvVar,pPath);
  264. }
  265. return (TRUE);
  266. }
  267. /* strcpyCDS - copies CDS paths
  268. *
  269. * This routine emulates how DOS was coping the directory path. It is
  270. * unclear if it is still necessary to do it this way.
  271. *
  272. * Entry -
  273. *
  274. * Exit
  275. * SUCCESS
  276. *
  277. * FAILURE
  278. */
  279. VOID strcpyCDS (PCDS source, LPSTR dest)
  280. {
  281. #ifdef FE_SB // for DBCS Directory name by v-hidekk 1994.5.23
  282. unsigned char ch;
  283. unsigned char ch2;
  284. #else // !FE_SB
  285. char ch;
  286. #endif // !FE_SB
  287. int index;
  288. index = source->CurDir_End;
  289. if (source->CurDir_Text[index]=='\\')
  290. index++;
  291. #ifdef FE_SB //for DBCS Directory by v-hidekk 1994.5.23
  292. // BUGBUG -- the code below is not equivalent to the code in Else clause
  293. // we need to check for 0x05 character preceded by '\\' and replace it
  294. // wth 0xE5
  295. while (ch = source->CurDir_Text[index]) {
  296. if (IsDBCSLeadByte(ch) ) {
  297. if( ch2 = source->CurDir_Text[index+1] ) {
  298. *dest++ = ch;
  299. *dest++ = ch2;
  300. index+=2;
  301. }
  302. else {
  303. index++;
  304. }
  305. }
  306. else {
  307. *dest++ = (UCHAR)toupper(ch);
  308. index++;
  309. }
  310. }
  311. #else // !FE_SB
  312. while (ch = source->CurDir_Text[index]) {
  313. if ((ch == 0x05) && (source->CurDir_Text[index-1] == '\\')) {
  314. ch = (CHAR) 0xE5;
  315. }
  316. *dest++ = toupper(ch);
  317. index++;
  318. }
  319. #endif // !FE_SB
  320. *dest = ch; // trailing zero
  321. }
  322. /* GetCDSFromDrv - Updates current dir in CDS structure
  323. *
  324. * Entry - Drive = Physical Drive in question (0, 1 ...)
  325. *
  326. * Exit
  327. * SUCCESS - returns v86 pointer to CDS structure in DOS
  328. *
  329. * FAILURE - returns 0
  330. */
  331. PCDS GetCDSFromDrv (UCHAR Drive)
  332. {
  333. PCDS pCDS = NULL;
  334. static CHAR pPath[]="?:\\";
  335. CHAR chDrive;
  336. //
  337. // Is Drive valid?
  338. //
  339. if (Drive >= *(PUCHAR)DosWowData.lpCDSCount) {
  340. if (Drive <= 25) {
  341. chDrive = Drive + 'A';
  342. pPath[0] = chDrive;
  343. //
  344. // test to see if non-fixed/floppy drive exists
  345. //
  346. if ((*(PUCHAR)DosWowData.lpCurDrv == Drive) ||
  347. (GetDriveType(pPath) > 1)) {
  348. //
  349. // Network drive
  350. //
  351. pCDS = (PCDS) DosWowData.lpCDSBuffer;
  352. }
  353. }
  354. } else {
  355. #if NEC_98
  356. // This is updated a current dir in lpCDSBuffer or lpCDSFixedTable.
  357. // Then, The drive is checked the drive type and lpCDSCount(continuation drive).
  358. if (Drive <= 25)
  359. {
  360. chDrive = Drive + 'A';
  361. pPath[0] = chDrive;
  362. switch(GetDriveType(pPath))
  363. {
  364. case DRIVE_REMOTE:
  365. // NetWorkDrive
  366. pCDS = (PCDS) DosWowData.lpCDSBuffer;
  367. break;
  368. case DRIVE_REMOVABLE:
  369. case DRIVE_FIXED:
  370. case DRIVE_CDROM:
  371. case DRIVE_RAMDISK:
  372. pCDS = (PCDS) DosWowData.lpCDSFixedTable;
  373. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS_JPN)));
  374. break;
  375. }
  376. }
  377. #else // NEC_98
  378. chDrive = Drive + 'A';
  379. pPath[0] = chDrive;
  380. if ((Drive != 1) || (DRIVE_REMOVABLE == GetDriveType(pPath))) {
  381. //
  382. // Drive defined in fixed table
  383. //
  384. pCDS = (PCDS) DosWowData.lpCDSFixedTable;
  385. #ifdef FE_SB
  386. if (GetSystemDefaultLangID() == MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)) {
  387. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS_JPN)));
  388. }
  389. else
  390. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS)));
  391. #else
  392. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS)));
  393. #endif
  394. }
  395. #endif // NEC_98
  396. }
  397. return (pCDS);
  398. }
  399. /* DosWowSetDefaultDrive - Emulate DOS set default drive call
  400. *
  401. * Entry -
  402. * BYTE DriveNum; = drive number to switch to
  403. *
  404. * Exit
  405. * returns client AX
  406. *
  407. */
  408. ULONG DosWowSetDefaultDrive(UCHAR Drive)
  409. {
  410. PCDS pCDS;
  411. if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
  412. if (GetCurrentDir (pCDS, Drive)) {
  413. if (*(PUCHAR)DosWowData.lpCurDrv != Drive) {
  414. // The upper bit in the TDB_Drive byte is used to indicate
  415. // that the current drive and directory information in the
  416. // TDB is stale. Turn it off here.
  417. // what is the curdir for this drive ?
  418. //
  419. CHAR szPath[MAX_PATH] = "?:\\";
  420. PTDB pTDB;
  421. if (*pCurTDB) {
  422. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  423. if (TDB_SIGNATURE == pTDB->TDB_sig) {
  424. if ((pTDB->TDB_Drive & TDB_DIR_VALID) &&
  425. (Drive == (pTDB->TDB_Drive & ~TDB_DIR_VALID))) {
  426. // update cds with current stuff here
  427. szPath[0] = 'A' + Drive;
  428. strcpy(&szPath[2], pTDB->TDB_LFNDirectory);
  429. // this call also updates the current dos drive
  430. DosWowUpdateCDSDir(Drive, szPath);
  431. Dumpdir("SetDefaultDrive(TDB->CDS): Drive %x", szPath, (UINT)Drive);
  432. return(Drive);
  433. }
  434. }
  435. }
  436. szPath[0] = Drive + 'A';
  437. if ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
  438. strcpy(&szPath[3], CurDirs[Drive]);
  439. }
  440. else { // grab one from CDS
  441. strcpyCDS(pCDS, &szPath[3]);
  442. }
  443. // update TDB to be in-sync with the cds
  444. Dumpdir("SetDefaultDrive(CDS->TDB): Drive %x", szPath, (UINT)Drive);
  445. *(PUCHAR)DosWowData.lpCurDrv = Drive;
  446. DosWowUpdateTDBDir(Drive, szPath);
  447. }
  448. }
  449. }
  450. return (*(PUCHAR)DosWowData.lpCurDrv);
  451. }
  452. #ifdef DEBUG
  453. VOID __cdecl
  454. Dumpdir(LPSTR pszfn, LPSTR pszDir, ...)
  455. {
  456. PTDB pTDB;
  457. char szMod[9];
  458. char s[256];
  459. va_list va;
  460. if (NULL != WOW32_strchr(pszfn, '%')) {
  461. va_start(va, pszDir);
  462. wvsprintf(s, pszfn, va);
  463. va_end(va);
  464. pszfn = s;
  465. }
  466. LOGDEBUG(CURDIR_LOGLEVEL, ("%s: ", pszfn));
  467. if (*pCurTDB) {
  468. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  469. if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) {
  470. WOW32_strncpy(szMod, pTDB->TDB_ModName, 8);
  471. szMod[8] = '\0';
  472. LOGDEBUG(CURDIR_LOGLEVEL, ("CurTDB: %x (%s) ", (DWORD)*pCurTDB, szMod));
  473. LOGDEBUG(CURDIR_LOGLEVEL, ("Drv %x Dir %s\n", (DWORD)pTDB->TDB_Drive, pTDB->TDB_LFNDirectory));
  474. }
  475. }
  476. else {
  477. LOGDEBUG(CURDIR_LOGLEVEL, ("CurTDB: NULL\n"));
  478. }
  479. LOGDEBUG(CURDIR_LOGLEVEL, ("%s: ", pszfn));
  480. if (*pCurDirOwner) {
  481. pTDB = (PTDB)SEGPTR(*pCurDirOwner,0);
  482. if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) {
  483. WOW32_strncpy(szMod, pTDB->TDB_ModName, 8);
  484. szMod[8] = '\0';
  485. LOGDEBUG(CURDIR_LOGLEVEL, ("CurDirOwn: %x (%s) ", (DWORD)*pCurDirOwner, szMod));
  486. LOGDEBUG(CURDIR_LOGLEVEL, ("Drive %x Dir %s\n", (DWORD)pTDB->TDB_Drive, pTDB->TDB_LFNDirectory));
  487. }
  488. }
  489. else {
  490. LOGDEBUG(CURDIR_LOGLEVEL, ("CurDirOwn: NULL\n"));
  491. }
  492. if (NULL != pszDir) {
  493. LOGDEBUG(CURDIR_LOGLEVEL, ("%s: %s\n", pszfn, pszDir));
  494. }
  495. }
  496. #endif
  497. // returns: current directory as done from the root
  498. BOOL DosWowGetTDBDir(UCHAR Drive, LPSTR pCurrentDirectory)
  499. {
  500. PTDB pTDB;
  501. if (*pCurTDB) {
  502. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  503. if (TDB_SIGNATURE == pTDB->TDB_sig &&
  504. (pTDB->TDB_Drive & TDB_DIR_VALID) &&
  505. ((pTDB->TDB_Drive & ~TDB_DIR_VALID) == Drive)) {
  506. strcpy(pCurrentDirectory, &pTDB->TDB_LFNDirectory[1]);
  507. // upper-case directory name
  508. WOW32_strupr(pCurrentDirectory);
  509. Dumpdir("DosWowGetTDBDir(CurTDB): Drive %x", pCurrentDirectory, (UINT)Drive);
  510. return(TRUE);
  511. }
  512. }
  513. return(FALSE);
  514. }
  515. /* DosWowGetCurrentDirectory - Emulate DOS Get current Directory call
  516. *
  517. *
  518. * Entry -
  519. * Drive - Drive number for directory request
  520. * pszDir- pointer to receive directory (MUST BE OF SIZE MAX_PATH)
  521. *
  522. * Exit
  523. * SUCCESS
  524. * 0
  525. *
  526. * FAILURE
  527. * system status code
  528. *
  529. */
  530. ULONG DosWowGetCurrentDirectory(UCHAR Drive, LPSTR pszDir)
  531. {
  532. PCDS pCDS;
  533. DWORD dwRet = 0xFFFF000F; // assume error
  534. //
  535. // Handle default drive value of 0
  536. //
  537. if (Drive == 0) {
  538. Drive = *(PUCHAR)DosWowData.lpCurDrv;
  539. } else {
  540. Drive--;
  541. }
  542. if (DosWowGetTDBDir(Drive, pszDir)) {
  543. return(0);
  544. }
  545. //
  546. // If the path has grown larger than the old MS-DOS path size, then
  547. // get the directory from our own private array.
  548. //
  549. if ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
  550. strcpy(pszDir, CurDirs[Drive]);
  551. Dumpdir("GetCurrentDirectory(CurDirs): Drive %x", pszDir, (UINT)Drive);
  552. return 0;
  553. }
  554. if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
  555. if (GetCurrentDir (pCDS, Drive)) {
  556. // for removable media we need to check that media is present.
  557. // fixed disks, network drives and CDROM drives are fixed drives in
  558. // DOS. sudeepb 30-Dec-1993
  559. if (!(pCDS->CurDir_Flags & CURDIR_NT_FIX)) {
  560. if(QueryCurrentDir (pCDS, Drive) == FALSE)
  561. return (dwRet); // fail
  562. }
  563. strcpyCDS(pCDS, pszDir);
  564. dwRet = 0;
  565. }
  566. }
  567. Dumpdir("GetCurrentDirectory: Drive %x", pszDir, (UINT)Drive);
  568. return (dwRet);
  569. }
  570. // updates current directory in CDS for the specified drive
  571. //
  572. VOID DosWowUpdateCDSDir(UCHAR Drive, LPSTR pszDir)
  573. {
  574. PCDS pCDS;
  575. if (NULL != (pCDS = GetCDSFromDrv(Drive))) {
  576. // cds retrieved successfully
  577. // now for this drive -- validate
  578. if (strlen(pszDir) > MAXIMUM_VDM_CURRENT_DIR+3) {
  579. if ((!CurDirs[Drive]) &&
  580. (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) {
  581. return;
  582. }
  583. strcpy(CurDirs[Drive], &pszDir[3]);
  584. // put a valid directory in cds just for robustness' sake
  585. WOW32_strncpy(&pCDS->CurDir_Text[0], pszDir, 3);
  586. pCDS->CurDir_Text[3] = 0;
  587. } else {
  588. if (CurDirs[Drive]) {
  589. free_w(CurDirs[Drive]);
  590. CurDirs[Drive] = NULL;
  591. }
  592. strcpy(&pCDS->CurDir_Text[0], pszDir);
  593. }
  594. *(PUCHAR)DosWowData.lpCurDrv = Drive;
  595. }
  596. }
  597. // updates current task's tdb with the current drive and directory information
  598. //
  599. //
  600. VOID DosWowUpdateTDBDir(UCHAR Drive, LPSTR pszDir)
  601. {
  602. PTDB pTDB;
  603. if (*pCurTDB) {
  604. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  605. if (TDB_SIGNATURE == pTDB->TDB_sig) {
  606. // So TDB should be updated IF the current drive is
  607. // indeed the drive we're updating a directory for
  608. if (*(PUCHAR)DosWowData.lpCurDrv == Drive) { // or valid and it's current drive
  609. pTDB->TDB_Drive = Drive | TDB_DIR_VALID;
  610. strcpy(pTDB->TDB_LFNDirectory, pszDir+2);
  611. *pCurDirOwner = *pCurTDB;
  612. }
  613. }
  614. }
  615. }
  616. /* DosWowSetCurrentDirectory - Emulate DOS Set current Directory call
  617. *
  618. *
  619. * Entry -
  620. * lpDosDirectory - pointer to new DOS directory
  621. *
  622. * Exit
  623. * SUCCESS
  624. * 0
  625. *
  626. * FAILURE
  627. * system status code
  628. *
  629. */
  630. extern NTSTATUS demSetCurrentDirectoryLCDS(UCHAR, LPSTR);
  631. ULONG DosWowSetCurrentDirectory(LPSTR pszDir)
  632. {
  633. PCDS pCDS;
  634. UCHAR Drive;
  635. LPTSTR pLast;
  636. PSTR lpDirName;
  637. UCHAR szPath[MAX_PATH];
  638. DWORD dwRet = 0xFFFF0003; // assume error
  639. static CHAR EnvVar[] = "=?:";
  640. BOOL ItsANamedPipe = FALSE;
  641. BOOL fSetDirectory = TRUE; // try mapping directory from 9x special path to nt if false
  642. if (':' == pszDir[1]) {
  643. Drive = toupper(pszDir[0]) - 'A';
  644. } else {
  645. if (IS_ASCII_PATH_SEPARATOR(pszDir[0]) &&
  646. IS_ASCII_PATH_SEPARATOR(pszDir[1])) {
  647. return dwRet; // can't update dos curdir with UNC
  648. }
  649. Drive = *(PUCHAR)DosWowData.lpCurDrv;
  650. }
  651. if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
  652. lpDirName = NormalizeDosPath(pszDir, Drive, &ItsANamedPipe);
  653. GetFullPathNameOem(lpDirName, MAX_PATH, szPath, &pLast);
  654. fSetDirectory = SetCurrentDir(szPath,Drive);
  655. if (!fSetDirectory) {
  656. //
  657. // If set directory with the given path failed it might be one of the
  658. // 9x special path, so try mapping it to NT special path
  659. // i.e. c:\winnt\startm~1 becomes c:\docume~1\alluse~1\startm~1
  660. //
  661. UCHAR szMappedPath[MAX_PATH];
  662. if( W32Map9xSpecialPath(szPath,szMappedPath) ){
  663. strcpy(szPath,szMappedPath);
  664. fSetDirectory = SetCurrentDir(szPath,Drive);
  665. }
  666. }
  667. if (fSetDirectory) {
  668. //
  669. // If the directory is growing larger than the old MS-DOS max,
  670. // then remember the path in our own array. If it is shrinking,
  671. // then free up the string we allocated earlier.
  672. //
  673. if (strlen(szPath) > MAXIMUM_VDM_CURRENT_DIR+3) {
  674. if ((!CurDirs[Drive]) &&
  675. (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) {
  676. return dwRet;
  677. }
  678. strcpy(CurDirs[Drive], &szPath[3]);
  679. // put a valid directory in cds just for robustness' sake
  680. WOW32_strncpy(&pCDS->CurDir_Text[0], szPath, 3);
  681. pCDS->CurDir_Text[3] = 0;
  682. } else {
  683. if (CurDirs[Drive]) {
  684. free_w(CurDirs[Drive]);
  685. CurDirs[Drive] = NULL;
  686. }
  687. strcpy(&pCDS->CurDir_Text[0], szPath);
  688. }
  689. dwRet = 0;
  690. //
  691. // Update kernel16's "directory owner" with the current TDB.
  692. //
  693. Dumpdir("SetCurrentDirectory", szPath);
  694. DosWowUpdateTDBDir(Drive, szPath);
  695. // now update dem
  696. demSetCurrentDirectoryLCDS(Drive, szPath);
  697. }
  698. }
  699. return (dwRet);
  700. }
  701. //*****************************************************************************
  702. // UpdateDosCurrentDirectory -
  703. //
  704. // Entry -
  705. // fDir - specifies which directory should be updated
  706. //
  707. // Exit -
  708. // TRUE if the update was successful, FALSE otherwise
  709. //
  710. // Notes:
  711. //
  712. // There are actually three different current directories:
  713. // - The WIN32 current directory (this is really the one that counts)
  714. // - The DOS current directory, kept on a per drive basis
  715. // - The TASK current directory, kept in the TDB of a win16 task
  716. //
  717. // It is the responsibility of this routine to effectively copy the contents
  718. // of one of these directories into another. From where to where is determined
  719. // by the passed parameter, so it is the caller's responsibility to be sure
  720. // what exactly needs to be sync'd up with what.
  721. //
  722. //*****************************************************************************
  723. BOOL UpdateDosCurrentDirectory(UDCDFUNC fDir)
  724. {
  725. LONG lReturn = (LONG)FALSE;
  726. switch(fDir) {
  727. case DIR_DOS_TO_NT: {
  728. UCHAR szPath[MAX_PATH] = "?:\\";
  729. PTDB pTDB;
  730. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  731. Dumpdir("UpdateDosCurrentDir DOS->NT", NULL);
  732. if ((*pCurTDB) && (*pCurDirOwner != *pCurTDB)) {
  733. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  734. if ((TDB_SIGNATURE == pTDB->TDB_sig) &&
  735. (pTDB->TDB_Drive & TDB_DIR_VALID)) {
  736. szPath[0] = 'A' + (pTDB->TDB_Drive & ~TDB_DIR_VALID);
  737. strcpy(&szPath[2], pTDB->TDB_LFNDirectory);
  738. LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 1\n", szPath));
  739. if (SetCurrentDirectoryOem(szPath)) {
  740. // update cds and the current drive all at the same time
  741. DosWowUpdateCDSDir((UCHAR)(pTDB->TDB_Drive & ~TDB_DIR_VALID), szPath);
  742. // set the new curdir owner
  743. *pCurDirOwner = *pCurTDB;
  744. }
  745. break; // EXIT case
  746. }
  747. }
  748. szPath[0] = *(PUCHAR)DosWowData.lpCurDrv + 'A';
  749. if (CurDirs[*(PUCHAR)DosWowData.lpCurDrv]) {
  750. strcpy(&szPath[3], CurDirs[*(PUCHAR)DosWowData.lpCurDrv]);
  751. LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 2\n", szPath));
  752. DosWowUpdateTDBDir(*(PUCHAR)DosWowData.lpCurDrv, szPath);
  753. SetCurrentDirectoryOem(CurDirs[*(PUCHAR)DosWowData.lpCurDrv]);
  754. lReturn = TRUE;
  755. break;
  756. }
  757. if (DosWowGetCurrentDirectory(0, &szPath[3])) {
  758. LOGDEBUG(LOG_ERROR, ("DowWowGetCurrentDirectory failed\n"));
  759. } else {
  760. // set the current directory owner so that when the
  761. // task switch occurs -- i21 handler knows to set
  762. // the current dir
  763. LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 3\n", szPath));
  764. DosWowUpdateTDBDir(*(PUCHAR)DosWowData.lpCurDrv, szPath);
  765. SetCurrentDirectoryOem(szPath);
  766. lReturn = TRUE;
  767. }
  768. break;
  769. }
  770. case DIR_NT_TO_DOS: {
  771. UCHAR szPath[MAX_PATH];
  772. if (!GetCurrentDirectoryOem(MAX_PATH, szPath)) {
  773. LOGDEBUG(LOG_ERROR, ("DowWowSetCurrentDirectory failed\n"));
  774. } else {
  775. Dumpdir("UpdateDosCurrentDirectory NT->DOS", szPath);
  776. LOGDEBUG(LOG_WARNING, ("UpdateDosCurrentDirectory NT->DOS: %s\n", &szPath[0]));
  777. if (szPath[1] == ':') {
  778. DosWowSetDefaultDrive((UCHAR) (toupper(szPath[0]) - 'A'));
  779. DosWowSetCurrentDirectory(szPath);
  780. lReturn = TRUE;
  781. }
  782. }
  783. break;
  784. }
  785. }
  786. return (BOOL)lReturn;
  787. }
  788. /***************************************************************************
  789. Stub entry points (called by KRNL386, 286 via thunks)
  790. ***************************************************************************/
  791. /* WK32SetDefaultDrive - Emulate DOS set default drive call
  792. *
  793. * Entry -
  794. * BYTE DriveNum; = drive number to switch to
  795. *
  796. * Exit
  797. * returns client AX
  798. *
  799. */
  800. ULONG FASTCALL WK32SetDefaultDrive(PVDMFRAME pFrame)
  801. {
  802. PWOWSETDEFAULTDRIVE16 parg16;
  803. UCHAR Drive;
  804. GETARGPTR(pFrame, sizeof(WOWSETDEFAULTDRIVE16), parg16);
  805. Drive = (UCHAR) parg16->wDriveNum;
  806. FREEARGPTR(parg16);
  807. return (DosWowSetDefaultDrive (Drive));
  808. }
  809. /* WK32SetCurrentDirectory - Emulate DOS set current Directory call
  810. *
  811. * Entry -
  812. * DWORD lpDosData = pointer to DosWowData structure in DOS
  813. * parg16->lpDosDirectory - pointer to real mode DOS pdb variable
  814. * parg16->wNewDirectory - 16-bit pmode selector for new Directory
  815. *
  816. * Exit
  817. * SUCCESS
  818. * 0
  819. *
  820. * FAILURE
  821. * system status code
  822. *
  823. */
  824. ULONG FASTCALL WK32SetCurrentDirectory(PVDMFRAME pFrame)
  825. {
  826. PWOWSETCURRENTDIRECTORY16 parg16;
  827. LPSTR pszDir;
  828. ULONG dwRet;
  829. GETARGPTR(pFrame, sizeof(WOWSETCURRENTDIRECTORY16), parg16);
  830. GETVDMPTR(parg16->lpCurDir, 4, pszDir);
  831. FREEARGPTR(parg16);
  832. dwRet = DosWowSetCurrentDirectory (pszDir);
  833. FREEVDMPTR(pszDir);
  834. return(dwRet);
  835. }
  836. /* WK32GetCurrentDirectory - Emulate DOS Get current Directory call
  837. *
  838. *
  839. * Entry -
  840. * DWORD lpDosData = pointer to DosWowData structure in DOS
  841. * parg16->lpCurDir - pointer to buffer to receive directory
  842. * parg16->wDriveNum - Drive number requested
  843. * Upper bit (0x80) is set if the caller wants long path
  844. *
  845. * Exit
  846. * SUCCESS
  847. * 0
  848. *
  849. * FAILURE
  850. * DOS error code (000f)
  851. *
  852. */
  853. ULONG FASTCALL WK32GetCurrentDirectory(PVDMFRAME pFrame)
  854. {
  855. PWOWGETCURRENTDIRECTORY16 parg16;
  856. LPSTR pszDir;
  857. UCHAR Drive;
  858. ULONG dwRet;
  859. GETARGPTR(pFrame, sizeof(WOWGETCURRENTDIRECTORY16), parg16);
  860. GETVDMPTR(parg16->lpCurDir, 4, pszDir);
  861. Drive = (UCHAR) parg16->wDriveNum;
  862. FREEARGPTR(parg16);
  863. if (Drive<0x80) {
  864. UCHAR ChkDrive;
  865. //
  866. // Normal GetCurrentDirectory call.
  867. // If the path has grown larger than the old MS-DOS path size, then
  868. // return error, just like on win95.
  869. //
  870. if (Drive == 0) {
  871. ChkDrive = *(PUCHAR)DosWowData.lpCurDrv;
  872. } else {
  873. ChkDrive = Drive-1;
  874. }
  875. if ((Drive<MAX_DOS_DRIVES) && CurDirs[ChkDrive]) {
  876. return 0xFFFF000F;
  877. }
  878. } else {
  879. //
  880. // the caller wants the long path path
  881. //
  882. Drive &= 0x7f;
  883. }
  884. dwRet = DosWowGetCurrentDirectory (Drive, pszDir);
  885. FREEVDMPTR(pszDir);
  886. return(dwRet);
  887. }
  888. /* WK32GetCurrentDate - Emulate DOS Get current Date call
  889. *
  890. *
  891. * Entry -
  892. *
  893. * Exit
  894. * return value is packed with date information
  895. *
  896. */
  897. ULONG FASTCALL WK32GetCurrentDate(PVDMFRAME pFrame)
  898. {
  899. SYSTEMTIME systemtime;
  900. UNREFERENCED_PARAMETER(pFrame);
  901. GetLocalTime(&systemtime);
  902. return ((DWORD) (systemtime.wYear << 16 |
  903. systemtime.wDay << 8 |
  904. systemtime.wMonth << 4 |
  905. systemtime.wDayOfWeek
  906. ));
  907. }
  908. #if 0
  909. /* The following routine will probably never be used because we allow
  910. WOW apps to set a local time within the WOW. So we really want apps
  911. that read the time with int21 to go down to DOS where this local time
  912. is kept. But if we ever want to return the win32 time, then this
  913. routine will do it. */
  914. /* WK32GetCurrentTime - Emulate DOS Get current Time call
  915. *
  916. *
  917. * Entry -
  918. *
  919. * Exit
  920. * return value is packed with time information
  921. *
  922. */
  923. ULONG FASTCALL WK32GetCurrentTime(PVDMFRAME pFrame)
  924. {
  925. SYSTEMTIME systemtime;
  926. UNREFERENCED_PARAMETER(pFrame);
  927. GetLocalTime(&systemtime);
  928. return ((DWORD) (systemtime.wHour << 24 |
  929. systemtime.wMinute << 16 |
  930. systemtime.wSecond << 8 |
  931. systemtime.wMilliseconds/10
  932. ));
  933. }
  934. #endif
  935. /* WK32DeviceIOCTL - Emulate misc. DOS IOCTLs
  936. *
  937. * Entry -
  938. * BYTE DriveNum; = drive number
  939. *
  940. * Exit
  941. * returns client AX
  942. *
  943. */
  944. ULONG FASTCALL WK32DeviceIOCTL(PVDMFRAME pFrame)
  945. {
  946. PWOWDEVICEIOCTL16 parg16;
  947. UCHAR Drive;
  948. UCHAR Cmd;
  949. DWORD dwReturn = 0xFFFF0001; // error invalid function
  950. UINT uiDriveStatus;
  951. static CHAR pPath[]="?:\\";
  952. GETARGPTR(pFrame, sizeof(WOWDEVICEIOCTL16), parg16);
  953. Cmd = (UCHAR) parg16->wCmd;
  954. Drive = (UCHAR) parg16->wDriveNum;
  955. FREEARGPTR(parg16);
  956. if (Cmd != 8) { // Does Device Use Removeable Media
  957. return (dwReturn);
  958. }
  959. if (Drive == 0) {
  960. Drive = *(PUCHAR)DosWowData.lpCurDrv;
  961. } else {
  962. Drive--;
  963. }
  964. pPath[0] = Drive + 'A';
  965. uiDriveStatus = GetDriveType(pPath);
  966. if ((uiDriveStatus == 0) || (uiDriveStatus == 1)) {
  967. return (0xFFFF000F); // error invalid drive
  968. }
  969. if (uiDriveStatus == DRIVE_REMOVABLE) {
  970. dwReturn = 0;
  971. } else {
  972. dwReturn = 1;
  973. }
  974. return (dwReturn);
  975. }
  976. BOOL DosWowDoDirectHDPopup(VOID)
  977. {
  978. BOOL fNoPopupFlag;
  979. fNoPopupFlag = !!(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_NODIRECTHDPOPUP);
  980. LOGDEBUG(0, ("direct hd access popup flag: %s\n", fNoPopupFlag ? "TRUE" : "FALSE"));
  981. return(!fNoPopupFlag);
  982. }