/* wdos.c - DOS realted functions for WOW * * Modification History * * Sudeepb 23-Aug-1991 Created */ #include "precomp.h" #pragma hdrstop #include "curdir.h" MODNAME(wdos.c); ULONG demClientErrorEx (HANDLE hFile, CHAR chDrive, BOOL bSetRegs); extern DOSWOWDATA DosWowData; extern PWORD16 pCurTDB, pCurDirOwner; // // This is our local array of current directory strings. A particular entry // is only used if the directory becomes longer than the old MS-DOS limit // of 67 characters. // #define MAX_DOS_DRIVES 26 LPSTR CurDirs[MAX_DOS_DRIVES] = {NULL}; VOID DosWowUpdateTDBDir(UCHAR Drive, LPSTR pszDir); VOID DosWowUpdateCDSDir(UCHAR Drive, LPSTR pszDir); #ifdef DEBUG VOID __cdecl Dumpdir(LPSTR pszfn, LPSTR pszDir, ...); #else #define Dumpdir // #endif // // modify this to change all the current directory spew's logging level // #define CURDIR_LOGLEVEL 4 /* First, a brief explanation on Windows and current directory * * 1. Windows keeps a single current directory (and drive off course) per * application. All the "other" drives are shared between the apps and * current dirs on them could change without further notice, such that * if app "Abra" has c as it's current drive and "c:\foo" is it's current * dir, and another app "Cadabra" has d as it's current drive and "d:\bar" * as it's current dir, then this is what apps get in return to the respective * system calls: * App Call Param result * Cadabra GetCurrentDirectory c: c:\foo * Abra SetCurrentDirectory c:\foobar * Cadabra GetCurrentDirectory c: c:\foobar * Abra SetCurrentDirectory d:\test * Abra GetCurrentDirectory d: d:\test * Cadabra GetCurrentDirectory d: d:\bar <- d is it's current drive! * * 2. Windows is a "non-preemptive" multitasking OS. Remember that for later. * * 3. Tasks are id'd by their respective TDB's which have these interesting * members (see tdb16.h for the complete list): * * TDB_Drive * TDB_LFNDirectory * * when the high bit of the TDB_Drive is set (TDB_DIR_VALID) -- TDB_LFNDirectory * is a valid current directory for the TDB_Drive (which is app's current * drive). The drive itself (0-based drive number) is stored in * TDB_Drive & ~TDB_DIR_VALID * * 4. Who touches TDB_Drive ? * SaveState code -- which is called when the task is being switched away *from* * it looks to see if info on current drive and directory in TDB is stale (via * the TDB_DIR_VALID bit) and calls GetDefaultDrive and GetCurrentDirectory to * make sure what's in TDB is valid * * 5. Task switching * When task resumes it's running due to explanation above -- it has valid * TDB_Drive in it. When the very first call to the relevant i21 is being * made -- kernel looks at the owner of the current drive (kernel variable) * and if some other task owns the current drive/directory -- it makes calls * to wow to set current drive/dir from the TDB (which is sure valid at * this point). Current Drive owner is set to the current task so that * the next time around this call is not performed -- and since windows does * not allow task preemptions -- any calls to set drive/directory are not * reflected upon tdb up until the task switch time. * * 6. WOW considerations * We in WOW have a great deal of hassle due to a number of APIs that are * not called from i21 handler but rather deal with file i/o and other * issues that depend upon Win32 current directory. Lo and behold we have * an UpdateDosCurrentDirectory call that we make before and after the call * to certain Win32 apis (which were found by trial and error) * The logic inside is that we always try to keep as much sync as possible * between TDB, CDS and Win32. * * 7. CurDirs * CDS can only accomodate current dirs which are up to 64 chars in length * hence there is an array of CurDirs which is filled on a per-need basis * for those drives that have curdir lengths > 64+3 chars * * 8. Belief * I profoundly believe that the above information is sufficient by large * to successfully troubleshoot all the "current directory" issues that may * arise :-) * * 9. Thanks * Goes to Neil and Dave for all the insight and patience that made all these * wonderful discoveries possible. * * -- VadimB, This day -- July, the 28th 1997 */ /* GetCurrentDir - Updatess current dir in CDS structure * * Entry - pcds = pointer to CDS * chDrive = Physical Drive in question (0, 1 ...) * * Exit * SUCCESS - returns TRUE * * FAILURE - returns FALSE */ BOOL GetCurrentDir (PCDS pcds, UCHAR Drive) { static CHAR EnvVar[] = "=?:"; DWORD EnvVarLen; BOOL bStatus = TRUE; UCHAR FixedCount; int i; PCDS pcdstemp; FixedCount = *(PUCHAR) DosWowData.lpCDSCount; // // from Macro.Asm in DOS: // ; Sudeepb 20-Dec-1991 ; Added for redirected drives // ; We always sync the redirected drives. Local drives are sync // ; as per the curdir_tosync flag and SCS_ToSync // if (*(PUCHAR)DosWowData.lpSCS_ToSync) { #ifdef FE_SB if (GetSystemDefaultLangID() == MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)) { PCDS_JPN pcdstemp_jpn; pcdstemp_jpn = (PCDS_JPN) DosWowData.lpCDSFixedTable; for (i=0;i < (int)FixedCount; i++, pcdstemp_jpn++) pcdstemp_jpn->CurDirJPN_Flags |= CURDIR_TOSYNC; } else { pcdstemp = (PCDS) DosWowData.lpCDSFixedTable; for (i=0;i < (int)FixedCount; i++, pcdstemp++) pcdstemp->CurDir_Flags |= CURDIR_TOSYNC; } #else pcdstemp = (PCDS) DosWowData.lpCDSFixedTable; for (i=0;i < (int)FixedCount; i++, pcdstemp++) pcdstemp->CurDir_Flags |= CURDIR_TOSYNC; #endif // Mark tosync in network drive as well pcdstemp = (PCDS)DosWowData.lpCDSBuffer; pcdstemp->CurDir_Flags |= CURDIR_TOSYNC; *(PUCHAR)DosWowData.lpSCS_ToSync = 0; } // If CDS needs to be synched or if the requested drive is different // then the the drive being used by NetCDS go refresh the CDS. if ((pcds->CurDir_Flags & CURDIR_TOSYNC) || ((Drive >= FixedCount) && (pcds->CurDir_Text[0] != (Drive + 'A') && pcds->CurDir_Text[0] != (Drive + 'a')))) { // validate media EnvVar[1] = Drive + 'A'; if((EnvVarLen = GetEnvironmentVariableOem (EnvVar, (LPSTR)pcds, MAXIMUM_VDM_CURRENT_DIR+3)) == 0){ // if its not in env then and drive exist then we have'nt // yet touched it. pcds->CurDir_Text[0] = EnvVar[1]; pcds->CurDir_Text[1] = ':'; pcds->CurDir_Text[2] = '\\'; pcds->CurDir_Text[3] = 0; SetEnvironmentVariableOem ((LPSTR)EnvVar,(LPSTR)pcds); } if (EnvVarLen > MAXIMUM_VDM_CURRENT_DIR+3) { // // The current directory on this drive is too long to fit in the // cds. That's ok for a win16 app in general, since it won't be // using the cds in this case. But just to be more robust, put // a valid directory in the cds instead of just truncating it on // the off chance that it gets used. // pcds->CurDir_Text[0] = EnvVar[1]; pcds->CurDir_Text[1] = ':'; pcds->CurDir_Text[2] = '\\'; pcds->CurDir_Text[3] = 0; } pcds->CurDir_Flags &= 0xFFFF - CURDIR_TOSYNC; pcds->CurDir_End = 2; } if (!bStatus) { *(PUCHAR)DosWowData.lpDrvErr = ERROR_INVALID_DRIVE; } return (bStatus); } /* SetCurrentDir - Set the current directory * * * Entry - lpBuf = pointer to string specifying new directory * chDrive = Physical Drive in question (0, 1 ...) * * Exit * SUCCESS returns TRUE * FAILURE returns FALSE * */ BOOL SetCurrentDir (LPSTR lpBuf, UCHAR Drive) { static CHAR EnvVar[] = "=?:"; CHAR chDrive = Drive + 'A'; BOOL bRet; // ok -- we are setting the current directory ONLY if the drive // is the current drive for the app if (*(PUCHAR)DosWowData.lpCurDrv == Drive) { // if on the current drive--go win32 bRet = SetCurrentDirectoryOem(lpBuf); } else { // verify it's a valid dir DWORD dwAttributes; dwAttributes = GetFileAttributesOem(lpBuf); bRet = (0xffffffff != dwAttributes) && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY); } if (!bRet) { demClientErrorEx(INVALID_HANDLE_VALUE, chDrive, FALSE); return(FALSE); } EnvVar[1] = chDrive; bRet = SetEnvironmentVariableOem((LPSTR)EnvVar,lpBuf); return (bRet); } /* QueryCurrentDir - Verifies current dir provided in CDS structure * for $CURRENT_DIR * * First Validates Media, if invalid -> i24 error * Next Validates Path, if invalid set path to root (not an error) * * Entry - Client (DS:SI) Buffer to CDS path to verify * Client (AL) Physical Drive in question (A=0, B=1, ...) * * Exit * SUCCESS * Client (CY) = 0 * * FAILURE * Client (CY) = 1 , I24 drive invalid */ BOOL QueryCurrentDir (PCDS pcds, UCHAR Drive) { DWORD dw; CHAR chDrive; static CHAR pPath[]="?:\\"; static CHAR EnvVar[] = "=?:"; // validate media chDrive = Drive + 'A'; pPath[0] = chDrive; dw = GetFileAttributesOem(pPath); if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY)) { demClientErrorEx(INVALID_HANDLE_VALUE, chDrive, FALSE); return (FALSE); } // if invalid path, set path to the root // reset CDS, and win32 env for win32 dw = GetFileAttributesOem(pcds->CurDir_Text); if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY)) { strcpy(pcds->CurDir_Text, pPath); pcds->CurDir_End = 2; EnvVar[1] = chDrive; SetEnvironmentVariableOem(EnvVar,pPath); } return (TRUE); } /* strcpyCDS - copies CDS paths * * This routine emulates how DOS was coping the directory path. It is * unclear if it is still necessary to do it this way. * * Entry - * * Exit * SUCCESS * * FAILURE */ VOID strcpyCDS (PCDS source, LPSTR dest) { #ifdef FE_SB // for DBCS Directory name by v-hidekk 1994.5.23 unsigned char ch; unsigned char ch2; #else // !FE_SB char ch; #endif // !FE_SB int index; index = source->CurDir_End; if (source->CurDir_Text[index]=='\\') index++; #ifdef FE_SB //for DBCS Directory by v-hidekk 1994.5.23 // BUGBUG -- the code below is not equivalent to the code in Else clause // we need to check for 0x05 character preceded by '\\' and replace it // wth 0xE5 while (ch = source->CurDir_Text[index]) { if (IsDBCSLeadByte(ch) ) { if( ch2 = source->CurDir_Text[index+1] ) { *dest++ = ch; *dest++ = ch2; index+=2; } else { index++; } } else { *dest++ = (UCHAR)toupper(ch); index++; } } #else // !FE_SB while (ch = source->CurDir_Text[index]) { if ((ch == 0x05) && (source->CurDir_Text[index-1] == '\\')) { ch = (CHAR) 0xE5; } *dest++ = toupper(ch); index++; } #endif // !FE_SB *dest = ch; // trailing zero } /* GetCDSFromDrv - Updates current dir in CDS structure * * Entry - Drive = Physical Drive in question (0, 1 ...) * * Exit * SUCCESS - returns v86 pointer to CDS structure in DOS * * FAILURE - returns 0 */ PCDS GetCDSFromDrv (UCHAR Drive) { PCDS pCDS = NULL; static CHAR pPath[]="?:\\"; CHAR chDrive; // // Is Drive valid? // if (Drive >= *(PUCHAR)DosWowData.lpCDSCount) { if (Drive <= 25) { chDrive = Drive + 'A'; pPath[0] = chDrive; // // test to see if non-fixed/floppy drive exists // if ((*(PUCHAR)DosWowData.lpCurDrv == Drive) || (GetDriveType(pPath) > 1)) { // // Network drive // pCDS = (PCDS) DosWowData.lpCDSBuffer; } } } else { #if NEC_98 // This is updated a current dir in lpCDSBuffer or lpCDSFixedTable. // Then, The drive is checked the drive type and lpCDSCount(continuation drive). if (Drive <= 25) { chDrive = Drive + 'A'; pPath[0] = chDrive; switch(GetDriveType(pPath)) { case DRIVE_REMOTE: // NetWorkDrive pCDS = (PCDS) DosWowData.lpCDSBuffer; break; case DRIVE_REMOVABLE: case DRIVE_FIXED: case DRIVE_CDROM: case DRIVE_RAMDISK: pCDS = (PCDS) DosWowData.lpCDSFixedTable; pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS_JPN))); break; } } #else // NEC_98 chDrive = Drive + 'A'; pPath[0] = chDrive; if ((Drive != 1) || (DRIVE_REMOVABLE == GetDriveType(pPath))) { // // Drive defined in fixed table // pCDS = (PCDS) DosWowData.lpCDSFixedTable; #ifdef FE_SB if (GetSystemDefaultLangID() == MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)) { pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS_JPN))); } else pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS))); #else pCDS = (PCDS)((ULONG)pCDS + (Drive*sizeof(CDS))); #endif } #endif // NEC_98 } return (pCDS); } /* DosWowSetDefaultDrive - Emulate DOS set default drive call * * Entry - * BYTE DriveNum; = drive number to switch to * * Exit * returns client AX * */ ULONG DosWowSetDefaultDrive(UCHAR Drive) { PCDS pCDS; if (NULL != (pCDS = GetCDSFromDrv (Drive))) { if (GetCurrentDir (pCDS, Drive)) { if (*(PUCHAR)DosWowData.lpCurDrv != Drive) { // The upper bit in the TDB_Drive byte is used to indicate // that the current drive and directory information in the // TDB is stale. Turn it off here. // what is the curdir for this drive ? // CHAR szPath[MAX_PATH] = "?:\\"; PTDB pTDB; if (*pCurTDB) { pTDB = (PTDB)SEGPTR(*pCurTDB,0); if (TDB_SIGNATURE == pTDB->TDB_sig) { if ((pTDB->TDB_Drive & TDB_DIR_VALID) && (Drive == (pTDB->TDB_Drive & ~TDB_DIR_VALID))) { // update cds with current stuff here szPath[0] = 'A' + Drive; strcpy(&szPath[2], pTDB->TDB_LFNDirectory); // this call also updates the current dos drive DosWowUpdateCDSDir(Drive, szPath); Dumpdir("SetDefaultDrive(TDB->CDS): Drive %x", szPath, (UINT)Drive); return(Drive); } } } szPath[0] = Drive + 'A'; if ((DriveTDB): Drive %x", szPath, (UINT)Drive); *(PUCHAR)DosWowData.lpCurDrv = Drive; DosWowUpdateTDBDir(Drive, szPath); } } } return (*(PUCHAR)DosWowData.lpCurDrv); } #ifdef DEBUG VOID __cdecl Dumpdir(LPSTR pszfn, LPSTR pszDir, ...) { PTDB pTDB; char szMod[9]; char s[256]; va_list va; if (NULL != WOW32_strchr(pszfn, '%')) { va_start(va, pszDir); wvsprintf(s, pszfn, va); va_end(va); pszfn = s; } LOGDEBUG(CURDIR_LOGLEVEL, ("%s: ", pszfn)); if (*pCurTDB) { pTDB = (PTDB)SEGPTR(*pCurTDB,0); if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) { WOW32_strncpy(szMod, pTDB->TDB_ModName, 8); szMod[8] = '\0'; LOGDEBUG(CURDIR_LOGLEVEL, ("CurTDB: %x (%s) ", (DWORD)*pCurTDB, szMod)); LOGDEBUG(CURDIR_LOGLEVEL, ("Drv %x Dir %s\n", (DWORD)pTDB->TDB_Drive, pTDB->TDB_LFNDirectory)); } } else { LOGDEBUG(CURDIR_LOGLEVEL, ("CurTDB: NULL\n")); } LOGDEBUG(CURDIR_LOGLEVEL, ("%s: ", pszfn)); if (*pCurDirOwner) { pTDB = (PTDB)SEGPTR(*pCurDirOwner,0); if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) { WOW32_strncpy(szMod, pTDB->TDB_ModName, 8); szMod[8] = '\0'; LOGDEBUG(CURDIR_LOGLEVEL, ("CurDirOwn: %x (%s) ", (DWORD)*pCurDirOwner, szMod)); LOGDEBUG(CURDIR_LOGLEVEL, ("Drive %x Dir %s\n", (DWORD)pTDB->TDB_Drive, pTDB->TDB_LFNDirectory)); } } else { LOGDEBUG(CURDIR_LOGLEVEL, ("CurDirOwn: NULL\n")); } if (NULL != pszDir) { LOGDEBUG(CURDIR_LOGLEVEL, ("%s: %s\n", pszfn, pszDir)); } } #endif // returns: current directory as done from the root BOOL DosWowGetTDBDir(UCHAR Drive, LPSTR pCurrentDirectory) { PTDB pTDB; if (*pCurTDB) { pTDB = (PTDB)SEGPTR(*pCurTDB,0); if (TDB_SIGNATURE == pTDB->TDB_sig && (pTDB->TDB_Drive & TDB_DIR_VALID) && ((pTDB->TDB_Drive & ~TDB_DIR_VALID) == Drive)) { strcpy(pCurrentDirectory, &pTDB->TDB_LFNDirectory[1]); // upper-case directory name WOW32_strupr(pCurrentDirectory); Dumpdir("DosWowGetTDBDir(CurTDB): Drive %x", pCurrentDirectory, (UINT)Drive); return(TRUE); } } return(FALSE); } /* DosWowGetCurrentDirectory - Emulate DOS Get current Directory call * * * Entry - * Drive - Drive number for directory request * pszDir- pointer to receive directory (MUST BE OF SIZE MAX_PATH) * * Exit * SUCCESS * 0 * * FAILURE * system status code * */ ULONG DosWowGetCurrentDirectory(UCHAR Drive, LPSTR pszDir) { PCDS pCDS; DWORD dwRet = 0xFFFF000F; // assume error // // Handle default drive value of 0 // if (Drive == 0) { Drive = *(PUCHAR)DosWowData.lpCurDrv; } else { Drive--; } if (DosWowGetTDBDir(Drive, pszDir)) { return(0); } // // If the path has grown larger than the old MS-DOS path size, then // get the directory from our own private array. // if ((DriveCurDir_Flags & CURDIR_NT_FIX)) { if(QueryCurrentDir (pCDS, Drive) == FALSE) return (dwRet); // fail } strcpyCDS(pCDS, pszDir); dwRet = 0; } } Dumpdir("GetCurrentDirectory: Drive %x", pszDir, (UINT)Drive); return (dwRet); } // updates current directory in CDS for the specified drive // VOID DosWowUpdateCDSDir(UCHAR Drive, LPSTR pszDir) { PCDS pCDS; if (NULL != (pCDS = GetCDSFromDrv(Drive))) { // cds retrieved successfully // now for this drive -- validate if (strlen(pszDir) > MAXIMUM_VDM_CURRENT_DIR+3) { if ((!CurDirs[Drive]) && (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) { return; } strcpy(CurDirs[Drive], &pszDir[3]); // put a valid directory in cds just for robustness' sake WOW32_strncpy(&pCDS->CurDir_Text[0], pszDir, 3); pCDS->CurDir_Text[3] = 0; } else { if (CurDirs[Drive]) { free_w(CurDirs[Drive]); CurDirs[Drive] = NULL; } strcpy(&pCDS->CurDir_Text[0], pszDir); } *(PUCHAR)DosWowData.lpCurDrv = Drive; } } // updates current task's tdb with the current drive and directory information // // VOID DosWowUpdateTDBDir(UCHAR Drive, LPSTR pszDir) { PTDB pTDB; if (*pCurTDB) { pTDB = (PTDB)SEGPTR(*pCurTDB,0); if (TDB_SIGNATURE == pTDB->TDB_sig) { // So TDB should be updated IF the current drive is // indeed the drive we're updating a directory for if (*(PUCHAR)DosWowData.lpCurDrv == Drive) { // or valid and it's current drive pTDB->TDB_Drive = Drive | TDB_DIR_VALID; strcpy(pTDB->TDB_LFNDirectory, pszDir+2); *pCurDirOwner = *pCurTDB; } } } } /* DosWowSetCurrentDirectory - Emulate DOS Set current Directory call * * * Entry - * lpDosDirectory - pointer to new DOS directory * * Exit * SUCCESS * 0 * * FAILURE * system status code * */ extern NTSTATUS demSetCurrentDirectoryLCDS(UCHAR, LPSTR); ULONG DosWowSetCurrentDirectory(LPSTR pszDir) { PCDS pCDS; UCHAR Drive; LPTSTR pLast; PSTR lpDirName; UCHAR szPath[MAX_PATH]; DWORD dwRet = 0xFFFF0003; // assume error static CHAR EnvVar[] = "=?:"; BOOL ItsANamedPipe = FALSE; BOOL fSetDirectory = TRUE; // try mapping directory from 9x special path to nt if false if (':' == pszDir[1]) { Drive = toupper(pszDir[0]) - 'A'; } else { if (IS_ASCII_PATH_SEPARATOR(pszDir[0]) && IS_ASCII_PATH_SEPARATOR(pszDir[1])) { return dwRet; // can't update dos curdir with UNC } Drive = *(PUCHAR)DosWowData.lpCurDrv; } if (NULL != (pCDS = GetCDSFromDrv (Drive))) { lpDirName = NormalizeDosPath(pszDir, Drive, &ItsANamedPipe); GetFullPathNameOem(lpDirName, MAX_PATH, szPath, &pLast); fSetDirectory = SetCurrentDir(szPath,Drive); if (!fSetDirectory) { // // If set directory with the given path failed it might be one of the // 9x special path, so try mapping it to NT special path // i.e. c:\winnt\startm~1 becomes c:\docume~1\alluse~1\startm~1 // UCHAR szMappedPath[MAX_PATH]; if( W32Map9xSpecialPath(szPath,szMappedPath) ){ strcpy(szPath,szMappedPath); fSetDirectory = SetCurrentDir(szPath,Drive); } } if (fSetDirectory) { // // If the directory is growing larger than the old MS-DOS max, // then remember the path in our own array. If it is shrinking, // then free up the string we allocated earlier. // if (strlen(szPath) > MAXIMUM_VDM_CURRENT_DIR+3) { if ((!CurDirs[Drive]) && (NULL == (CurDirs[Drive] = malloc_w(MAX_PATH)))) { return dwRet; } strcpy(CurDirs[Drive], &szPath[3]); // put a valid directory in cds just for robustness' sake WOW32_strncpy(&pCDS->CurDir_Text[0], szPath, 3); pCDS->CurDir_Text[3] = 0; } else { if (CurDirs[Drive]) { free_w(CurDirs[Drive]); CurDirs[Drive] = NULL; } strcpy(&pCDS->CurDir_Text[0], szPath); } dwRet = 0; // // Update kernel16's "directory owner" with the current TDB. // Dumpdir("SetCurrentDirectory", szPath); DosWowUpdateTDBDir(Drive, szPath); // now update dem demSetCurrentDirectoryLCDS(Drive, szPath); } } return (dwRet); } //***************************************************************************** // UpdateDosCurrentDirectory - // // Entry - // fDir - specifies which directory should be updated // // Exit - // TRUE if the update was successful, FALSE otherwise // // Notes: // // There are actually three different current directories: // - The WIN32 current directory (this is really the one that counts) // - The DOS current directory, kept on a per drive basis // - The TASK current directory, kept in the TDB of a win16 task // // It is the responsibility of this routine to effectively copy the contents // of one of these directories into another. From where to where is determined // by the passed parameter, so it is the caller's responsibility to be sure // what exactly needs to be sync'd up with what. // //***************************************************************************** BOOL UpdateDosCurrentDirectory(UDCDFUNC fDir) { LONG lReturn = (LONG)FALSE; switch(fDir) { case DIR_DOS_TO_NT: { UCHAR szPath[MAX_PATH] = "?:\\"; PTDB pTDB; WOW32ASSERT(DosWowData.lpCurDrv != (ULONG) NULL); Dumpdir("UpdateDosCurrentDir DOS->NT", NULL); if ((*pCurTDB) && (*pCurDirOwner != *pCurTDB)) { pTDB = (PTDB)SEGPTR(*pCurTDB,0); if ((TDB_SIGNATURE == pTDB->TDB_sig) && (pTDB->TDB_Drive & TDB_DIR_VALID)) { szPath[0] = 'A' + (pTDB->TDB_Drive & ~TDB_DIR_VALID); strcpy(&szPath[2], pTDB->TDB_LFNDirectory); LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 1\n", szPath)); if (SetCurrentDirectoryOem(szPath)) { // update cds and the current drive all at the same time DosWowUpdateCDSDir((UCHAR)(pTDB->TDB_Drive & ~TDB_DIR_VALID), szPath); // set the new curdir owner *pCurDirOwner = *pCurTDB; } break; // EXIT case } } szPath[0] = *(PUCHAR)DosWowData.lpCurDrv + 'A'; if (CurDirs[*(PUCHAR)DosWowData.lpCurDrv]) { strcpy(&szPath[3], CurDirs[*(PUCHAR)DosWowData.lpCurDrv]); LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 2\n", szPath)); DosWowUpdateTDBDir(*(PUCHAR)DosWowData.lpCurDrv, szPath); SetCurrentDirectoryOem(CurDirs[*(PUCHAR)DosWowData.lpCurDrv]); lReturn = TRUE; break; } if (DosWowGetCurrentDirectory(0, &szPath[3])) { LOGDEBUG(LOG_ERROR, ("DowWowGetCurrentDirectory failed\n")); } else { // set the current directory owner so that when the // task switch occurs -- i21 handler knows to set // the current dir LOGDEBUG(CURDIR_LOGLEVEL, ("UpdateDosCurrentDirectory: DOS->NT %s, case 3\n", szPath)); DosWowUpdateTDBDir(*(PUCHAR)DosWowData.lpCurDrv, szPath); SetCurrentDirectoryOem(szPath); lReturn = TRUE; } break; } case DIR_NT_TO_DOS: { UCHAR szPath[MAX_PATH]; if (!GetCurrentDirectoryOem(MAX_PATH, szPath)) { LOGDEBUG(LOG_ERROR, ("DowWowSetCurrentDirectory failed\n")); } else { Dumpdir("UpdateDosCurrentDirectory NT->DOS", szPath); LOGDEBUG(LOG_WARNING, ("UpdateDosCurrentDirectory NT->DOS: %s\n", &szPath[0])); if (szPath[1] == ':') { DosWowSetDefaultDrive((UCHAR) (toupper(szPath[0]) - 'A')); DosWowSetCurrentDirectory(szPath); lReturn = TRUE; } } break; } } return (BOOL)lReturn; } /*************************************************************************** Stub entry points (called by KRNL386, 286 via thunks) ***************************************************************************/ /* WK32SetDefaultDrive - Emulate DOS set default drive call * * Entry - * BYTE DriveNum; = drive number to switch to * * Exit * returns client AX * */ ULONG FASTCALL WK32SetDefaultDrive(PVDMFRAME pFrame) { PWOWSETDEFAULTDRIVE16 parg16; UCHAR Drive; GETARGPTR(pFrame, sizeof(WOWSETDEFAULTDRIVE16), parg16); Drive = (UCHAR) parg16->wDriveNum; FREEARGPTR(parg16); return (DosWowSetDefaultDrive (Drive)); } /* WK32SetCurrentDirectory - Emulate DOS set current Directory call * * Entry - * DWORD lpDosData = pointer to DosWowData structure in DOS * parg16->lpDosDirectory - pointer to real mode DOS pdb variable * parg16->wNewDirectory - 16-bit pmode selector for new Directory * * Exit * SUCCESS * 0 * * FAILURE * system status code * */ ULONG FASTCALL WK32SetCurrentDirectory(PVDMFRAME pFrame) { PWOWSETCURRENTDIRECTORY16 parg16; LPSTR pszDir; ULONG dwRet; GETARGPTR(pFrame, sizeof(WOWSETCURRENTDIRECTORY16), parg16); GETVDMPTR(parg16->lpCurDir, 4, pszDir); FREEARGPTR(parg16); dwRet = DosWowSetCurrentDirectory (pszDir); FREEVDMPTR(pszDir); return(dwRet); } /* WK32GetCurrentDirectory - Emulate DOS Get current Directory call * * * Entry - * DWORD lpDosData = pointer to DosWowData structure in DOS * parg16->lpCurDir - pointer to buffer to receive directory * parg16->wDriveNum - Drive number requested * Upper bit (0x80) is set if the caller wants long path * * Exit * SUCCESS * 0 * * FAILURE * DOS error code (000f) * */ ULONG FASTCALL WK32GetCurrentDirectory(PVDMFRAME pFrame) { PWOWGETCURRENTDIRECTORY16 parg16; LPSTR pszDir; UCHAR Drive; ULONG dwRet; GETARGPTR(pFrame, sizeof(WOWGETCURRENTDIRECTORY16), parg16); GETVDMPTR(parg16->lpCurDir, 4, pszDir); Drive = (UCHAR) parg16->wDriveNum; FREEARGPTR(parg16); if (Drive<0x80) { UCHAR ChkDrive; // // Normal GetCurrentDirectory call. // If the path has grown larger than the old MS-DOS path size, then // return error, just like on win95. // if (Drive == 0) { ChkDrive = *(PUCHAR)DosWowData.lpCurDrv; } else { ChkDrive = Drive-1; } if ((DrivewCmd; Drive = (UCHAR) parg16->wDriveNum; FREEARGPTR(parg16); if (Cmd != 8) { // Does Device Use Removeable Media return (dwReturn); } if (Drive == 0) { Drive = *(PUCHAR)DosWowData.lpCurDrv; } else { Drive--; } pPath[0] = Drive + 'A'; uiDriveStatus = GetDriveType(pPath); if ((uiDriveStatus == 0) || (uiDriveStatus == 1)) { return (0xFFFF000F); // error invalid drive } if (uiDriveStatus == DRIVE_REMOVABLE) { dwReturn = 0; } else { dwReturn = 1; } return (dwReturn); } BOOL DosWowDoDirectHDPopup(VOID) { BOOL fNoPopupFlag; fNoPopupFlag = !!(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_NODIRECTHDPOPUP); LOGDEBUG(0, ("direct hd access popup flag: %s\n", fNoPopupFlag ? "TRUE" : "FALSE")); return(!fNoPopupFlag); }