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.

1213 lines
34 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 haven't
  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 = GetFileAttributesOemSys(lpBuf, TRUE);
  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 = GetFileAttributesOemSys(pPath, TRUE);
  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 = GetFileAttributesOemSys(pcds->CurDir_Text, TRUE);
  258. if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY))
  259. {
  260. strncpy(pcds->CurDir_Text, pPath, DIRSTRLEN);
  261. pcds->CurDir_Text[DIRSTRLEN-1] = '\0';
  262. pcds->CurDir_End = 2;
  263. EnvVar[1] = chDrive;
  264. SetEnvironmentVariableOem(EnvVar,pPath);
  265. }
  266. return (TRUE);
  267. }
  268. /* strcpyCDS - copies CDS paths
  269. *
  270. * This routine emulates how DOS was coping the directory path. It is
  271. * unclear if it is still necessary to do it this way.
  272. *
  273. * Entry -
  274. *
  275. * Exit
  276. * SUCCESS
  277. *
  278. * FAILURE
  279. */
  280. VOID strcpyCDS (PCDS source, LPSTR dest)
  281. {
  282. #ifdef FE_SB // for DBCS Directory name by v-hidekk 1994.5.23
  283. unsigned char ch;
  284. unsigned char ch2;
  285. #else // !FE_SB
  286. char ch;
  287. #endif // !FE_SB
  288. int index;
  289. index = source->CurDir_End;
  290. if (source->CurDir_Text[index]=='\\')
  291. index++;
  292. #ifdef FE_SB //for DBCS Directory by v-hidekk 1994.5.23
  293. // BUGBUG -- the code below is not equivalent to the code in Else clause
  294. // we need to check for 0x05 character preceded by '\\' and replace it
  295. // wth 0xE5
  296. while (ch = source->CurDir_Text[index]) {
  297. if (IsDBCSLeadByte(ch) ) {
  298. if( ch2 = source->CurDir_Text[index+1] ) {
  299. *dest++ = ch;
  300. *dest++ = ch2;
  301. index+=2;
  302. }
  303. else {
  304. index++;
  305. }
  306. }
  307. else {
  308. *dest++ = (UCHAR)toupper(ch);
  309. index++;
  310. }
  311. }
  312. #else // !FE_SB
  313. while (ch = source->CurDir_Text[index]) {
  314. if ((ch == 0x05) && (source->CurDir_Text[index-1] == '\\')) {
  315. ch = (CHAR) 0xE5;
  316. }
  317. *dest++ = toupper(ch);
  318. index++;
  319. }
  320. #endif // !FE_SB
  321. *dest = ch; // trailing zero
  322. }
  323. /* GetCDSFromDrv - Updates current dir in CDS structure
  324. *
  325. * Entry - Drive = Physical Drive in question (0, 1 ...)
  326. *
  327. * Exit
  328. * SUCCESS - returns v86 pointer to CDS structure in DOS
  329. *
  330. * FAILURE - returns 0
  331. */
  332. PCDS GetCDSFromDrv (UCHAR Drive)
  333. {
  334. PCDS pCDS = NULL;
  335. static CHAR pPath[]="?:\\";
  336. CHAR chDrive;
  337. //
  338. // Is Drive valid?
  339. //
  340. if (Drive >= *(PUCHAR)DosWowData.lpCDSCount) {
  341. if (Drive <= 25) {
  342. chDrive = Drive + 'A';
  343. pPath[0] = chDrive;
  344. //
  345. // test to see if non-fixed/floppy drive exists
  346. //
  347. if ((*(PUCHAR)DosWowData.lpCurDrv == Drive) ||
  348. (GetDriveType(pPath) > 1)) {
  349. //
  350. // Network drive
  351. //
  352. pCDS = (PCDS) DosWowData.lpCDSBuffer;
  353. }
  354. }
  355. } else {
  356. chDrive = Drive + 'A';
  357. pPath[0] = chDrive;
  358. if ((Drive != 1) || (DRIVE_REMOVABLE == GetDriveType(pPath))) {
  359. //
  360. // Drive defined in fixed table
  361. //
  362. pCDS = (PCDS) DosWowData.lpCDSFixedTable;
  363. #ifdef FE_SB
  364. if (GetSystemDefaultLangID() == MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)) {
  365. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS_JPN)));
  366. }
  367. else
  368. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS)));
  369. #else
  370. pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS)));
  371. #endif
  372. }
  373. }
  374. return (pCDS);
  375. }
  376. /* DosWowSetDefaultDrive - Emulate DOS set default drive call
  377. *
  378. * Entry -
  379. * BYTE DriveNum; = drive number to switch to
  380. *
  381. * Exit
  382. * returns client AX
  383. *
  384. */
  385. ULONG DosWowSetDefaultDrive(UCHAR Drive)
  386. {
  387. PCDS pCDS;
  388. if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
  389. if (GetCurrentDir (pCDS, Drive)) {
  390. if (*(PUCHAR)DosWowData.lpCurDrv != Drive) {
  391. // The upper bit in the TDB_Drive byte is used to indicate
  392. // that the current drive and directory information in the
  393. // TDB is stale. Turn it off here.
  394. // what is the curdir for this drive ?
  395. //
  396. CHAR szPath[MAX_PATH] = "?:\\";
  397. PTDB pTDB;
  398. if (*pCurTDB) {
  399. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  400. if (TDB_SIGNATURE == pTDB->TDB_sig) {
  401. if ((pTDB->TDB_Drive & TDB_DIR_VALID) &&
  402. (Drive == (pTDB->TDB_Drive & ~TDB_DIR_VALID))) {
  403. // update cds with current stuff here
  404. szPath[0] = 'A' + Drive;
  405. strncpy(&szPath[2],pTDB->TDB_LFNDirectory,MAX_PATH-2);
  406. szPath[MAX_PATH-1] = '\0';
  407. // this call also updates the current dos drive
  408. DosWowUpdateCDSDir(Drive, szPath);
  409. Dumpdir("SetDefaultDrive(TDB->CDS): Drive %x", szPath, (UINT)Drive);
  410. return(Drive);
  411. }
  412. }
  413. }
  414. szPath[0] = Drive + 'A';
  415. if ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
  416. strncpy(&szPath[3], CurDirs[Drive], MAX_PATH-3);
  417. szPath[MAX_PATH-1] = '\0';
  418. }
  419. else { // grab one from CDS
  420. strcpyCDS(pCDS, &szPath[3]);
  421. }
  422. // update TDB to be in-sync with the cds
  423. Dumpdir("SetDefaultDrive(CDS->TDB): Drive %x", szPath, (UINT)Drive);
  424. *(PUCHAR)DosWowData.lpCurDrv = Drive;
  425. DosWowUpdateTDBDir(Drive, szPath);
  426. }
  427. }
  428. }
  429. return (*(PUCHAR)DosWowData.lpCurDrv);
  430. }
  431. #ifdef DEBUG
  432. VOID __cdecl
  433. Dumpdir(LPSTR pszfn, LPSTR pszDir, ...)
  434. {
  435. PTDB pTDB;
  436. char szMod[9];
  437. char s[256];
  438. va_list va;
  439. if (NULL != WOW32_strchr(pszfn, '%')) {
  440. va_start(va, pszDir);
  441. wvsprintf(s, pszfn, va);
  442. va_end(va);
  443. pszfn = s;
  444. }
  445. LOGDEBUG(CURDIR_LOGLEVEL, ("%s: ", pszfn));
  446. if (*pCurTDB) {
  447. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  448. if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) {
  449. WOW32_strncpy(szMod, pTDB->TDB_ModName, 8);
  450. szMod[8] = '\0';
  451. LOGDEBUG(CURDIR_LOGLEVEL, ("CurTDB: %x (%s) ", (DWORD)*pCurTDB, szMod));
  452. LOGDEBUG(CURDIR_LOGLEVEL, ("Drv %x Dir %s\n", (DWORD)pTDB->TDB_Drive, pTDB->TDB_LFNDirectory));
  453. }
  454. }
  455. else {
  456. LOGDEBUG(CURDIR_LOGLEVEL, ("CurTDB: NULL\n"));
  457. }
  458. LOGDEBUG(CURDIR_LOGLEVEL, ("%s: ", pszfn));
  459. if (*pCurDirOwner) {
  460. pTDB = (PTDB)SEGPTR(*pCurDirOwner,0);
  461. if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) {
  462. WOW32_strncpy(szMod, pTDB->TDB_ModName, 8);
  463. szMod[8] = '\0';
  464. LOGDEBUG(CURDIR_LOGLEVEL, ("CurDirOwn: %x (%s) ", (DWORD)*pCurDirOwner, szMod));
  465. LOGDEBUG(CURDIR_LOGLEVEL, ("Drive %x Dir %s\n", (DWORD)pTDB->TDB_Drive, pTDB->TDB_LFNDirectory));
  466. }
  467. }
  468. else {
  469. LOGDEBUG(CURDIR_LOGLEVEL, ("CurDirOwn: NULL\n"));
  470. }
  471. if (NULL != pszDir) {
  472. LOGDEBUG(CURDIR_LOGLEVEL, ("%s: %s\n", pszfn, pszDir));
  473. }
  474. }
  475. #endif
  476. // returns: current directory as done from the root
  477. BOOL DosWowGetTDBDir(UCHAR Drive, LPSTR pCurrentDirectory)
  478. {
  479. PTDB pTDB;
  480. if (*pCurTDB) {
  481. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  482. if (TDB_SIGNATURE == pTDB->TDB_sig &&
  483. (pTDB->TDB_Drive & TDB_DIR_VALID) &&
  484. ((pTDB->TDB_Drive & ~TDB_DIR_VALID) == Drive)) {
  485. // Note: Everyone that calls this function does so with a array of
  486. // MAX_PATH but pass the address as &psDirPath[3]
  487. strcpy(pCurrentDirectory, &pTDB->TDB_LFNDirectory[1]);
  488. // upper-case directory name
  489. WOW32_strupr(pCurrentDirectory);
  490. Dumpdir("DosWowGetTDBDir(CurTDB): Drive %x", pCurrentDirectory, (UINT)Drive);
  491. return(TRUE);
  492. }
  493. }
  494. return(FALSE);
  495. }
  496. /* DosWowGetCurrentDirectory - Emulate DOS Get current Directory call
  497. *
  498. *
  499. * Entry -
  500. * Drive - Drive number for directory request
  501. * pszDir- pointer to receive directory (MUST BE OF SIZE MAX_PATH)
  502. *
  503. * Exit
  504. * SUCCESS
  505. * 0
  506. *
  507. * FAILURE
  508. * system status code
  509. *
  510. */
  511. ULONG DosWowGetCurrentDirectory(UCHAR Drive, LPSTR pszDir)
  512. {
  513. PCDS pCDS;
  514. DWORD dwRet = 0xFFFF000F; // assume error
  515. //
  516. // Handle default drive value of 0
  517. //
  518. if (Drive == 0) {
  519. Drive = *(PUCHAR)DosWowData.lpCurDrv;
  520. } else {
  521. Drive--;
  522. }
  523. if (DosWowGetTDBDir(Drive, pszDir)) {
  524. return(0);
  525. }
  526. //
  527. // If the path has grown larger than the old MS-DOS path size, then
  528. // get the directory from our own private array.
  529. //
  530. if ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
  531. strcpy(pszDir, CurDirs[Drive]);
  532. Dumpdir("GetCurrentDirectory(CurDirs): Drive %x", pszDir, (UINT)Drive);
  533. return 0;
  534. }
  535. if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
  536. if (GetCurrentDir (pCDS, Drive)) {
  537. // for removable media we need to check that media is present.
  538. // fixed disks, network drives and CDROM drives are fixed drives in
  539. // DOS. sudeepb 30-Dec-1993
  540. if (!(pCDS->CurDir_Flags & CURDIR_NT_FIX)) {
  541. if(QueryCurrentDir (pCDS, Drive) == FALSE)
  542. return (dwRet); // fail
  543. }
  544. strcpyCDS(pCDS, pszDir);
  545. dwRet = 0;
  546. }
  547. }
  548. Dumpdir("GetCurrentDirectory: Drive %x", pszDir, (UINT)Drive);
  549. return (dwRet);
  550. }
  551. // updates current directory in CDS for the specified drive
  552. //
  553. VOID DosWowUpdateCDSDir(UCHAR Drive, LPSTR pszDir)
  554. {
  555. PCDS pCDS;
  556. if (NULL != (pCDS = GetCDSFromDrv(Drive))) {
  557. // cds retrieved successfully
  558. // now for this drive -- validate
  559. if (strlen(pszDir) > MAXIMUM_VDM_CURRENT_DIR+3) {
  560. if ((!CurDirs[Drive]) &&
  561. (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) {
  562. return;
  563. }
  564. strncpy(CurDirs[Drive], &pszDir[3], MAX_PATH);
  565. CurDirs[Drive][MAX_PATH-1] = '\0';
  566. // put a valid directory in cds just for robustness' sake
  567. WOW32_strncpy(&pCDS->CurDir_Text[0], pszDir, 3);
  568. pCDS->CurDir_Text[3] = 0;
  569. } else {
  570. if (CurDirs[Drive]) {
  571. free_w(CurDirs[Drive]);
  572. CurDirs[Drive] = NULL;
  573. }
  574. strncpy(&pCDS->CurDir_Text[0], pszDir, DIRSTRLEN);
  575. pCDS->CurDir_Text[DIRSTRLEN-1] = '\0';
  576. }
  577. *(PUCHAR)DosWowData.lpCurDrv = Drive;
  578. }
  579. }
  580. // updates current task's tdb with the current drive and directory information
  581. //
  582. //
  583. VOID DosWowUpdateTDBDir(UCHAR Drive, LPSTR pszDir)
  584. {
  585. PTDB pTDB;
  586. if (*pCurTDB) {
  587. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  588. if (TDB_SIGNATURE == pTDB->TDB_sig) {
  589. // So TDB should be updated IF the current drive is
  590. // indeed the drive we're updating a directory for
  591. if (*(PUCHAR)DosWowData.lpCurDrv == Drive) { // or valid and it's current drive
  592. pTDB->TDB_Drive = Drive | TDB_DIR_VALID;
  593. strncpy(pTDB->TDB_LFNDirectory, pszDir+2, LFN_DIR_LEN);
  594. pTDB->TDB_LFNDirectory[LFN_DIR_LEN-1] = '\0';
  595. *pCurDirOwner = *pCurTDB;
  596. }
  597. }
  598. }
  599. }
  600. /* DosWowSetCurrentDirectory - Emulate DOS Set current Directory call
  601. *
  602. *
  603. * Entry -
  604. * lpDosDirectory - pointer to new DOS directory
  605. *
  606. * Exit
  607. * SUCCESS
  608. * 0
  609. *
  610. * FAILURE
  611. * system status code
  612. *
  613. */
  614. ULONG DosWowSetCurrentDirectory(LPSTR pszDir)
  615. {
  616. PCDS pCDS;
  617. UCHAR Drive;
  618. LPTSTR pLast;
  619. PSTR lpDirName;
  620. UCHAR szPath[MAX_PATH];
  621. DWORD dwRet = 0xFFFF0003; // assume error
  622. static CHAR EnvVar[] = "=?:";
  623. BOOL ItsANamedPipe = FALSE;
  624. BOOL fSetDirectory = TRUE; // try mapping directory from 9x special path to nt if false
  625. if (':' == pszDir[1]) {
  626. Drive = toupper(pszDir[0]) - 'A';
  627. } else {
  628. if (IS_ASCII_PATH_SEPARATOR(pszDir[0]) &&
  629. IS_ASCII_PATH_SEPARATOR(pszDir[1])) {
  630. return dwRet; // can't update dos curdir with UNC
  631. }
  632. Drive = *(PUCHAR)DosWowData.lpCurDrv;
  633. }
  634. if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
  635. lpDirName = NormalizeDosPath(pszDir, Drive, &ItsANamedPipe);
  636. GetFullPathNameOemSys(lpDirName, MAX_PATH, szPath, &pLast, TRUE);
  637. fSetDirectory = SetCurrentDir(szPath,Drive);
  638. if (!fSetDirectory) {
  639. //
  640. // If set directory with the given path failed it might be one of the
  641. // 9x special path, so try mapping it to NT special path
  642. // i.e. c:\winnt\startm~1 becomes c:\docume~1\alluse~1\startm~1
  643. //
  644. UCHAR szMappedPath[MAX_PATH];
  645. if(W32Map9xSpecialPath(szPath,szMappedPath,sizeof(szMappedPath))) {
  646. strncpy(szPath, szMappedPath, MAX_PATH);
  647. szPath[MAX_PATH-1] = '\0';
  648. fSetDirectory = SetCurrentDir(szPath,Drive);
  649. }
  650. }
  651. if (fSetDirectory) {
  652. //
  653. // If the directory is growing larger than the old MS-DOS max,
  654. // then remember the path in our own array. If it is shrinking,
  655. // then free up the string we allocated earlier.
  656. //
  657. if (strlen(szPath) > MAXIMUM_VDM_CURRENT_DIR+3) {
  658. if ((!CurDirs[Drive]) &&
  659. (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) {
  660. return dwRet;
  661. }
  662. strncpy(CurDirs[Drive], &szPath[3], MAX_PATH);
  663. // put a valid directory in cds just for robustness' sake
  664. WOW32_strncpy(&pCDS->CurDir_Text[0], szPath, 3);
  665. pCDS->CurDir_Text[3] = 0;
  666. } else {
  667. if (CurDirs[Drive]) {
  668. free_w(CurDirs[Drive]);
  669. CurDirs[Drive] = NULL;
  670. }
  671. strcpy(&pCDS->CurDir_Text[0], szPath);
  672. }
  673. dwRet = 0;
  674. //
  675. // Update kernel16's "directory owner" with the current TDB.
  676. //
  677. Dumpdir("SetCurrentDirectory", szPath);
  678. DosWowUpdateTDBDir(Drive, szPath);
  679. }
  680. }
  681. return (dwRet);
  682. }
  683. //*****************************************************************************
  684. // UpdateDosCurrentDirectory -
  685. //
  686. // Entry -
  687. // fDir - specifies which directory should be updated
  688. //
  689. // Exit -
  690. // TRUE if the update was successful, FALSE otherwise
  691. //
  692. // Notes:
  693. //
  694. // There are actually three different current directories:
  695. // - The WIN32 current directory (this is really the one that counts)
  696. // - The DOS current directory, kept on a per drive basis
  697. // - The TASK current directory, kept in the TDB of a win16 task
  698. //
  699. // It is the responsibility of this routine to effectively copy the contents
  700. // of one of these directories into another. From where to where is determined
  701. // by the passed parameter, so it is the caller's responsibility to be sure
  702. // what exactly needs to be sync'd up with what.
  703. //
  704. //*****************************************************************************
  705. BOOL UpdateDosCurrentDirectory(UDCDFUNC fDir)
  706. {
  707. LONG lReturn = (LONG)FALSE;
  708. switch(fDir) {
  709. case DIR_DOS_TO_NT: {
  710. UCHAR szPath[MAX_PATH] = "?:\\";
  711. PTDB pTDB;
  712. WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL);
  713. Dumpdir("UpdateDosCurrentDir DOS->NT", NULL);
  714. if ((*pCurTDB) && (*pCurDirOwner != *pCurTDB)) {
  715. pTDB = (PTDB)SEGPTR(*pCurTDB,0);
  716. if ((TDB_SIGNATURE == pTDB->TDB_sig) &&
  717. (pTDB->TDB_Drive & TDB_DIR_VALID)) {
  718. szPath[0] = 'A' + (pTDB->TDB_Drive & ~TDB_DIR_VALID);
  719. strncpy(&szPath[2], pTDB->TDB_LFNDirectory, MAX_PATH-2);
  720. szPath[MAX_PATH-1] = '\0';
  721. LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 1\n", szPath));
  722. if (SetCurrentDirectoryOem(szPath)) {
  723. // update cds and the current drive all at the same time
  724. DosWowUpdateCDSDir((UCHAR)(pTDB->TDB_Drive & ~TDB_DIR_VALID), szPath);
  725. // set the new curdir owner
  726. *pCurDirOwner = *pCurTDB;
  727. }
  728. break; // EXIT case
  729. }
  730. }
  731. szPath[0] = *(PUCHAR)DosWowData.lpCurDrv + 'A';
  732. if (CurDirs[*(PUCHAR)DosWowData.lpCurDrv]) {
  733. strncpy(&szPath[3],
  734. CurDirs[*(PUCHAR)DosWowData.lpCurDrv],
  735. MAX_PATH-3);
  736. szPath[MAX_PATH-1] = '\0';
  737. LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 2\n", szPath));
  738. DosWowUpdateTDBDir(*(PUCHAR)DosWowData.lpCurDrv, szPath);
  739. SetCurrentDirectoryOem(CurDirs[*(PUCHAR)DosWowData.lpCurDrv]);
  740. lReturn = TRUE;
  741. break;
  742. }
  743. if (DosWowGetCurrentDirectory(0, &szPath[3])) {
  744. LOGDEBUG(LOG_ERROR, ("DowWowGetCurrentDirectory failed\n"));
  745. } else {
  746. // set the current directory owner so that when the
  747. // task switch occurs -- i21 handler knows to set
  748. // the current dir
  749. LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 3\n", szPath));
  750. DosWowUpdateTDBDir(*(PUCHAR)DosWowData.lpCurDrv, szPath);
  751. SetCurrentDirectoryOem(szPath);
  752. lReturn = TRUE;
  753. }
  754. break;
  755. }
  756. case DIR_NT_TO_DOS: {
  757. UCHAR szPath[MAX_PATH];
  758. if (!GetCurrentDirectoryOem(MAX_PATH, szPath)) {
  759. LOGDEBUG(LOG_ERROR, ("DowWowSetCurrentDirectory failed\n"));
  760. } else {
  761. Dumpdir("UpdateDosCurrentDirectory NT->DOS", szPath);
  762. LOGDEBUG(LOG_WARNING, ("UpdateDosCurrentDirectory NT->DOS: %s\n", &szPath[0]));
  763. if (szPath[1] == ':') {
  764. DosWowSetDefaultDrive((UCHAR) (toupper(szPath[0]) - 'A'));
  765. DosWowSetCurrentDirectory(szPath);
  766. lReturn = TRUE;
  767. }
  768. }
  769. break;
  770. }
  771. }
  772. return (BOOL)lReturn;
  773. }
  774. /***************************************************************************
  775. Stub entry points (called by KRNL386, 286 via thunks)
  776. ***************************************************************************/
  777. /* WK32SetDefaultDrive - Emulate DOS set default drive call
  778. *
  779. * Entry -
  780. * BYTE DriveNum; = drive number to switch to
  781. *
  782. * Exit
  783. * returns client AX
  784. *
  785. */
  786. ULONG FASTCALL WK32SetDefaultDrive(PVDMFRAME pFrame)
  787. {
  788. PWOWSETDEFAULTDRIVE16 parg16;
  789. UCHAR Drive;
  790. GETARGPTR(pFrame, sizeof(WOWSETDEFAULTDRIVE16), parg16);
  791. Drive = (UCHAR) parg16->wDriveNum;
  792. FREEARGPTR(parg16);
  793. return (DosWowSetDefaultDrive (Drive));
  794. }
  795. /* WK32SetCurrentDirectory - Emulate DOS set current Directory call
  796. *
  797. * Entry -
  798. * DWORD lpDosData = pointer to DosWowData structure in DOS
  799. * parg16->lpDosDirectory - pointer to real mode DOS pdb variable
  800. * parg16->wNewDirectory - 16-bit pmode selector for new Directory
  801. *
  802. * Exit
  803. * SUCCESS
  804. * 0
  805. *
  806. * FAILURE
  807. * system status code
  808. *
  809. */
  810. ULONG FASTCALL WK32SetCurrentDirectory(PVDMFRAME pFrame)
  811. {
  812. PWOWSETCURRENTDIRECTORY16 parg16;
  813. LPSTR pszDir;
  814. ULONG dwRet;
  815. GETARGPTR(pFrame, sizeof(WOWSETCURRENTDIRECTORY16), parg16);
  816. GETVDMPTR(parg16->lpCurDir, 4, pszDir);
  817. FREEARGPTR(parg16);
  818. dwRet = DosWowSetCurrentDirectory (pszDir);
  819. FREEVDMPTR(pszDir);
  820. return(dwRet);
  821. }
  822. /* WK32GetCurrentDirectory - Emulate DOS Get current Directory call
  823. *
  824. *
  825. * Entry -
  826. * DWORD lpDosData = pointer to DosWowData structure in DOS
  827. * parg16->lpCurDir - pointer to buffer to receive directory
  828. * parg16->wDriveNum - Drive number requested
  829. * Upper bit (0x80) is set if the caller wants long path
  830. *
  831. * Exit
  832. * SUCCESS
  833. * 0
  834. *
  835. * FAILURE
  836. * DOS error code (000f)
  837. *
  838. */
  839. ULONG FASTCALL WK32GetCurrentDirectory(PVDMFRAME pFrame)
  840. {
  841. PWOWGETCURRENTDIRECTORY16 parg16;
  842. LPSTR pszDir;
  843. UCHAR Drive;
  844. ULONG dwRet;
  845. GETARGPTR(pFrame, sizeof(WOWGETCURRENTDIRECTORY16), parg16);
  846. GETVDMPTR(parg16->lpCurDir, 4, pszDir);
  847. Drive = (UCHAR) parg16->wDriveNum;
  848. FREEARGPTR(parg16);
  849. if (Drive<0x80) {
  850. UCHAR ChkDrive;
  851. //
  852. // Normal GetCurrentDirectory call.
  853. // If the path has grown larger than the old MS-DOS path size, then
  854. // return error, just like on win95.
  855. //
  856. if (Drive == 0) {
  857. ChkDrive = *(PUCHAR)DosWowData.lpCurDrv;
  858. } else {
  859. ChkDrive = Drive-1;
  860. }
  861. if ((Drive<MAX_DOS_DRIVES) && CurDirs[ChkDrive]) {
  862. return 0xFFFF000F;
  863. }
  864. } else {
  865. //
  866. // the caller wants the long path path
  867. //
  868. Drive &= 0x7f;
  869. }
  870. dwRet = DosWowGetCurrentDirectory (Drive, pszDir);
  871. FREEVDMPTR(pszDir);
  872. return(dwRet);
  873. }
  874. /* WK32GetCurrentDate - Emulate DOS Get current Date call
  875. *
  876. *
  877. * Entry -
  878. *
  879. * Exit
  880. * return value is packed with date information
  881. *
  882. */
  883. ULONG FASTCALL WK32GetCurrentDate(PVDMFRAME pFrame)
  884. {
  885. SYSTEMTIME systemtime;
  886. UNREFERENCED_PARAMETER(pFrame);
  887. GetLocalTime(&systemtime);
  888. return ((DWORD) (systemtime.wYear << 16 |
  889. systemtime.wDay << 8 |
  890. systemtime.wMonth << 4 |
  891. systemtime.wDayOfWeek
  892. ));
  893. }
  894. #if 0
  895. /* The following routine will probably never be used because we allow
  896. WOW apps to set a local time within the WOW. So we really want apps
  897. that read the time with int21 to go down to DOS where this local time
  898. is kept. But if we ever want to return the win32 time, then this
  899. routine will do it. */
  900. /* WK32GetCurrentTime - Emulate DOS Get current Time call
  901. *
  902. *
  903. * Entry -
  904. *
  905. * Exit
  906. * return value is packed with time information
  907. *
  908. */
  909. ULONG FASTCALL WK32GetCurrentTime(PVDMFRAME pFrame)
  910. {
  911. SYSTEMTIME systemtime;
  912. UNREFERENCED_PARAMETER(pFrame);
  913. GetLocalTime(&systemtime);
  914. return ((DWORD) (systemtime.wHour << 24 |
  915. systemtime.wMinute << 16 |
  916. systemtime.wSecond << 8 |
  917. systemtime.wMilliseconds/10
  918. ));
  919. }
  920. #endif
  921. /* WK32DeviceIOCTL - Emulate misc. DOS IOCTLs
  922. *
  923. * Entry -
  924. * BYTE DriveNum; = drive number
  925. *
  926. * Exit
  927. * returns client AX
  928. *
  929. */
  930. ULONG FASTCALL WK32DeviceIOCTL(PVDMFRAME pFrame)
  931. {
  932. PWOWDEVICEIOCTL16 parg16;
  933. UCHAR Drive;
  934. UCHAR Cmd;
  935. DWORD dwReturn = 0xFFFF0001; // error invalid function
  936. UINT uiDriveStatus;
  937. static CHAR pPath[]="?:\\";
  938. GETARGPTR(pFrame, sizeof(WOWDEVICEIOCTL16), parg16);
  939. Cmd = (UCHAR) parg16->wCmd;
  940. Drive = (UCHAR) parg16->wDriveNum;
  941. FREEARGPTR(parg16);
  942. if (Cmd != 8) { // Does Device Use Removeable Media
  943. return (dwReturn);
  944. }
  945. if (Drive == 0) {
  946. Drive = *(PUCHAR)DosWowData.lpCurDrv;
  947. } else {
  948. Drive--;
  949. }
  950. pPath[0] = Drive + 'A';
  951. uiDriveStatus = DPM_GetDriveType(pPath);
  952. if ((uiDriveStatus == 0) || (uiDriveStatus == 1)) {
  953. return (0xFFFF000F); // error invalid drive
  954. }
  955. if (uiDriveStatus == DRIVE_REMOVABLE) {
  956. dwReturn = 0;
  957. } else {
  958. dwReturn = 1;
  959. }
  960. return (dwReturn);
  961. }
  962. BOOL DosWowDoDirectHDPopup(VOID)
  963. {
  964. BOOL fNoPopupFlag;
  965. fNoPopupFlag = !!(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_NODIRECTHDPOPUP);
  966. LOGDEBUG(0, ("direct hd access popup flag: %s\n", fNoPopupFlag ? "TRUE" : "FALSE"));
  967. return(!fNoPopupFlag);
  968. }