1237 lines
33 KiB
C
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);
|
|
}
|
|
|
|
|