windows-nt/Source/XPSP1/NT/base/mvdm/wow32/wdos.c
2020-09-26 16:20:57 +08:00

1237 lines
33 KiB
C

/* 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 ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
strcpy(&szPath[3], CurDirs[Drive]);
}
else { // grab one from CDS
strcpyCDS(pCDS, &szPath[3]);
}
// update TDB to be in-sync with the cds
Dumpdir("SetDefaultDrive(CDS->TDB): 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 ((Drive<MAX_DOS_DRIVES) && CurDirs[Drive]) {
strcpy(pszDir, CurDirs[Drive]);
Dumpdir("GetCurrentDirectory(CurDirs): Drive %x", pszDir, (UINT)Drive);
return 0;
}
if (NULL != (pCDS = GetCDSFromDrv (Drive))) {
if (GetCurrentDir (pCDS, Drive)) {
// for removable media we need to check that media is present.
// fixed disks, network drives and CDROM drives are fixed drives in
// DOS. sudeepb 30-Dec-1993
if (!(pCDS->CurDir_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 ((Drive<MAX_DOS_DRIVES) && CurDirs[ChkDrive]) {
return 0xFFFF000F;
}
} else {
//
// the caller wants the long path path
//
Drive &= 0x7f;
}
dwRet = DosWowGetCurrentDirectory (Drive, pszDir);
FREEVDMPTR(pszDir);
return(dwRet);
}
/* WK32GetCurrentDate - Emulate DOS Get current Date call
*
*
* Entry -
*
* Exit
* return value is packed with date information
*
*/
ULONG FASTCALL WK32GetCurrentDate(PVDMFRAME pFrame)
{
SYSTEMTIME systemtime;
UNREFERENCED_PARAMETER(pFrame);
GetLocalTime(&systemtime);
return ((DWORD) (systemtime.wYear << 16 |
systemtime.wDay << 8 |
systemtime.wMonth << 4 |
systemtime.wDayOfWeek
));
}
#if 0
/* The following routine will probably never be used because we allow
WOW apps to set a local time within the WOW. So we really want apps
that read the time with int21 to go down to DOS where this local time
is kept. But if we ever want to return the win32 time, then this
routine will do it. */
/* WK32GetCurrentTime - Emulate DOS Get current Time call
*
*
* Entry -
*
* Exit
* return value is packed with time information
*
*/
ULONG FASTCALL WK32GetCurrentTime(PVDMFRAME pFrame)
{
SYSTEMTIME systemtime;
UNREFERENCED_PARAMETER(pFrame);
GetLocalTime(&systemtime);
return ((DWORD) (systemtime.wHour << 24 |
systemtime.wMinute << 16 |
systemtime.wSecond << 8 |
systemtime.wMilliseconds/10
));
}
#endif
/* WK32DeviceIOCTL - Emulate misc. DOS IOCTLs
*
* Entry -
* BYTE DriveNum; = drive number
*
* Exit
* returns client AX
*
*/
ULONG FASTCALL WK32DeviceIOCTL(PVDMFRAME pFrame)
{
PWOWDEVICEIOCTL16 parg16;
UCHAR Drive;
UCHAR Cmd;
DWORD dwReturn = 0xFFFF0001; // error invalid function
UINT uiDriveStatus;
static CHAR pPath[]="?:\\";
GETARGPTR(pFrame, sizeof(WOWDEVICEIOCTL16), parg16);
Cmd = (UCHAR) parg16->wCmd;
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);
}