403 lines
11 KiB
C
403 lines
11 KiB
C
|
/* demerror.c - Error handling routines of DEM
|
|||
|
*
|
|||
|
* demSetHardErrorInfo
|
|||
|
* demClientError
|
|||
|
* demRetry
|
|||
|
*
|
|||
|
* Modification History:
|
|||
|
*
|
|||
|
* Sudeepb 27-Nov-1991 Created
|
|||
|
*/
|
|||
|
|
|||
|
#include "dem.h"
|
|||
|
#include "demmsg.h"
|
|||
|
|
|||
|
#include <softpc.h>
|
|||
|
|
|||
|
PVHE pHardErrPacket;
|
|||
|
PSYSDEV pDeviceChain;
|
|||
|
SAVEDEMWORLD RetryInfo;
|
|||
|
|
|||
|
CHAR GetDriveLetterByHandle(HANDLE hFile);
|
|||
|
VOID SubstituteDeviceName( PUNICODE_STRING InputDeviceName,
|
|||
|
LPSTR OutputDriveLetter);
|
|||
|
|
|||
|
/* demSetHardErrorInfo - Store away harderr related address of DOSKRNL
|
|||
|
*
|
|||
|
* Entry
|
|||
|
* Client (DS:DX) - VHE structure
|
|||
|
*
|
|||
|
* Exit
|
|||
|
* None
|
|||
|
*/
|
|||
|
|
|||
|
VOID demSetHardErrorInfo (VOID)
|
|||
|
{
|
|||
|
pHardErrPacket = (PVHE) GetVDMAddr (getDS(),getDX());
|
|||
|
pDeviceChain = (PSYSDEV) GetVDMAddr(getDS(),getBX());
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* demRetry - Retry the operation which last resulted in hard error
|
|||
|
*
|
|||
|
* Entry
|
|||
|
* None
|
|||
|
*
|
|||
|
* Exit
|
|||
|
* None
|
|||
|
*/
|
|||
|
|
|||
|
VOID demRetry (VOID)
|
|||
|
{
|
|||
|
ULONG iSvc;
|
|||
|
|
|||
|
demRestoreHardErrInfo ();
|
|||
|
iSvc = CurrentISVC;
|
|||
|
|
|||
|
#if DBG
|
|||
|
if(iSvc < SVC_DEMLASTSVC && (fShowSVCMsg & DEMSVCTRACE) &&
|
|||
|
apfnSVC[iSvc] != demNotYetImplemented){
|
|||
|
sprintf(demDebugBuffer,"demRetry:Retrying %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n",
|
|||
|
aSVCNames[iSvc],getAX(),getBX(),getCX(),getDX(),getDI(),getSI());
|
|||
|
OutputDebugStringOem(demDebugBuffer);
|
|||
|
sprintf(demDebugBuffer,"\tCS=%.4x IP=%.4x DS=%.4x ES=%.4x SS=%.4x SP=%.4x BP=%.4x\n",
|
|||
|
getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP());
|
|||
|
OutputDebugStringOem(demDebugBuffer);
|
|||
|
}
|
|||
|
|
|||
|
if (iSvc >= SVC_DEMLASTSVC || apfnSVC[iSvc] == demNotYetImplemented ){
|
|||
|
ASSERT(FALSE);
|
|||
|
setCF(1);
|
|||
|
setAX(0xff);
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
(apfnSVC [iSvc])();
|
|||
|
|
|||
|
#if DBG
|
|||
|
if((fShowSVCMsg & DEMSVCTRACE)){
|
|||
|
sprintf(demDebugBuffer,"demRetry:After %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n",
|
|||
|
aSVCNames[iSvc],getAX(),getBX(),getCX(),getDX(),getDI(),getSI());
|
|||
|
OutputDebugStringOem(demDebugBuffer);
|
|||
|
sprintf(demDebugBuffer,"\tCS=%.4x IP=%.4x DS=%.4x ES=%.4x SS=%.4x SP=%.4x BP=%.4x CF=%x\n",
|
|||
|
getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP(),getCF());
|
|||
|
OutputDebugStringOem(demDebugBuffer);
|
|||
|
}
|
|||
|
#endif
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* demClientError - Update client registers to signal error
|
|||
|
*
|
|||
|
* Entry
|
|||
|
* HANDLE hFile; file handle , if none == -1
|
|||
|
* char chDrive; drive letter , if none == -1
|
|||
|
*
|
|||
|
* Exit
|
|||
|
* Client (CF) = 1
|
|||
|
* Client (AX) = Error Code
|
|||
|
*
|
|||
|
* Notes
|
|||
|
* the following errors cause hard errors
|
|||
|
* errors above ERROR_GEN_FAILURE are mapped to general fail by the DOS
|
|||
|
*
|
|||
|
*
|
|||
|
* ERROR_WRITE_PROTECT 19L
|
|||
|
* ERROR_BAD_UNIT 20L
|
|||
|
* ERROR_NOT_READY 21L
|
|||
|
* ERROR_BAD_COMMAND 22L
|
|||
|
* ERROR_CRC 23L
|
|||
|
* ERROR_BAD_LENGTH 24L
|
|||
|
* ERROR_SEEK 25L
|
|||
|
* ERROR_NOT_DOS_DISK 26L
|
|||
|
* ERROR_SECTOR_NOT_FOUND 27L
|
|||
|
* ERROR_OUT_OF_PAPER 28L
|
|||
|
* ERROR_WRITE_FAULT 29L
|
|||
|
* ERROR_READ_FAULT 30L
|
|||
|
* ERROR_GEN_FAILURE 31L
|
|||
|
* ERROR_WRONG_DISK 34l
|
|||
|
* ERROR_NO_MEDIA_IN_DRIVE 1112l
|
|||
|
* #ifdef JAPAN
|
|||
|
* ERROR_UNRECOGNIZED_MEDIA 1785L
|
|||
|
* #ifdef JAPAN
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
VOID demClientError (HANDLE hFile, CHAR chDrive)
|
|||
|
{
|
|||
|
demClientErrorEx (hFile, chDrive, TRUE);
|
|||
|
}
|
|||
|
|
|||
|
ULONG demClientErrorEx (HANDLE hFile, CHAR chDrive, BOOL bSetRegs)
|
|||
|
{
|
|||
|
ULONG ulErrCode;
|
|||
|
|
|||
|
if(!(ulErrCode = GetLastError()))
|
|||
|
ulErrCode = ERROR_ACCESS_DENIED;
|
|||
|
|
|||
|
#ifdef JAPAN
|
|||
|
if ((ulErrCode < ERROR_WRITE_PROTECT || ulErrCode > ERROR_GEN_FAILURE)
|
|||
|
&& ulErrCode != ERROR_WRONG_DISK && ulErrCode != ERROR_UNRECOGNIZED_MEDIA)
|
|||
|
#else // !JAPAN
|
|||
|
if ((ulErrCode < ERROR_WRITE_PROTECT || ulErrCode > ERROR_GEN_FAILURE)
|
|||
|
&& ulErrCode != ERROR_WRONG_DISK )
|
|||
|
#endif // !JAPAN
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
if (fShowSVCMsg & DEMERROR) {
|
|||
|
sprintf(demDebugBuffer,"demClientErr: ErrCode=%ld\n", ulErrCode);
|
|||
|
OutputDebugStringOem(demDebugBuffer);
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (bSetRegs) {
|
|||
|
setAX((USHORT)ulErrCode);
|
|||
|
}
|
|||
|
}
|
|||
|
else { // handle hard error case
|
|||
|
if (ulErrCode > ERROR_GEN_FAILURE)
|
|||
|
ulErrCode = ERROR_GEN_FAILURE;
|
|||
|
|
|||
|
// Set the hard error flag
|
|||
|
pHardErrPacket->vhe_fbInt24 = 1;
|
|||
|
|
|||
|
// Get the drive letter
|
|||
|
if (hFile != INVALID_HANDLE_VALUE)
|
|||
|
chDrive = GetDriveLetterByHandle(hFile);
|
|||
|
|
|||
|
pHardErrPacket->vhe_bDriveNum = chDrive == -1
|
|||
|
? -1 : toupper(chDrive) - 'A';
|
|||
|
|
|||
|
// convert error code to i24 based error.
|
|||
|
ulErrCode -= ERROR_WRITE_PROTECT;
|
|||
|
pHardErrPacket->vhe_HrdErrCode = (UCHAR)ulErrCode;
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (fShowSVCMsg & DEMERROR) {
|
|||
|
sprintf(demDebugBuffer,
|
|||
|
"demClientErr HRDERR: DriveNum=%ld ErrCode=%ld\n",
|
|||
|
(DWORD)pHardErrPacket->vhe_bDriveNum,
|
|||
|
(DWORD)pHardErrPacket->vhe_HrdErrCode);
|
|||
|
OutputDebugStringOem(demDebugBuffer);
|
|||
|
}
|
|||
|
#endif
|
|||
|
// Save Away Information for possible retry operation
|
|||
|
demSaveHardErrInfo ();
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (bSetRegs)
|
|||
|
setCF(1);
|
|||
|
return (ulErrCode);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* GetDriveLetterByHandle
|
|||
|
*
|
|||
|
* retrieves the drive letter for the file handle
|
|||
|
* if its a remote drive or fails returns -1
|
|||
|
*/
|
|||
|
CHAR GetDriveLetterByHandle(HANDLE hFile)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG ul;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
FILE_FS_DEVICE_INFORMATION DeviceInfo;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
POBJECT_NAME_INFORMATION pObNameInfo;
|
|||
|
CHAR Buffer[MAX_PATH+sizeof(OBJECT_NAME_INFORMATION)];
|
|||
|
CHAR ch;
|
|||
|
|
|||
|
// if a remote drive return -1 for drive letter
|
|||
|
Status = NtQueryVolumeInformationFile(
|
|||
|
hFile,
|
|||
|
&IoStatusBlock,
|
|||
|
&DeviceInfo,
|
|||
|
sizeof(DeviceInfo),
|
|||
|
FileFsDeviceInformation );
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) &&
|
|||
|
DeviceInfo.Characteristics & FILE_REMOTE_DEVICE )
|
|||
|
return (CHAR) -1;
|
|||
|
|
|||
|
// get the name
|
|||
|
pObNameInfo = (POBJECT_NAME_INFORMATION)Buffer;
|
|||
|
Status = NtQueryObject( // get len of name
|
|||
|
hFile,
|
|||
|
ObjectNameInformation,
|
|||
|
pObNameInfo,
|
|||
|
sizeof(Buffer),
|
|||
|
&ul);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
return -1;
|
|||
|
|
|||
|
RtlUnicodeStringToAnsiString(&AnsiString, &(pObNameInfo->Name), TRUE);
|
|||
|
if (strstr(AnsiString.Buffer,"\\Device") == AnsiString.Buffer)
|
|||
|
SubstituteDeviceName(&(pObNameInfo->Name), AnsiString.Buffer);
|
|||
|
|
|||
|
ch = AnsiString.Buffer[0];
|
|||
|
RtlFreeAnsiString(&AnsiString);
|
|||
|
return ch;
|
|||
|
}
|
|||
|
|
|||
|
static WCHAR wszDosDevices[] = L"\\DosDevices\\?:";
|
|||
|
|
|||
|
/*
|
|||
|
* SubstituteDeviceName
|
|||
|
*
|
|||
|
* lifted this code from the user\harderror hard error thread
|
|||
|
*/
|
|||
|
VOID SubstituteDeviceName( PUNICODE_STRING InputDeviceName,
|
|||
|
LPSTR OutputDriveLetter )
|
|||
|
{
|
|||
|
UNICODE_STRING LinkName;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
OBJECT_ATTRIBUTES Obja;
|
|||
|
HANDLE LinkHandle;
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG i;
|
|||
|
PWCHAR p;
|
|||
|
PWCHAR pSlash = L"\\";
|
|||
|
WCHAR DeviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
|
|||
|
|
|||
|
/*
|
|||
|
* Ensure have trailing backslash
|
|||
|
*/
|
|||
|
|
|||
|
if (InputDeviceName->Buffer[(InputDeviceName->Length >>1) - 1] != *pSlash)
|
|||
|
RtlAppendUnicodeToString(InputDeviceName, pSlash);
|
|||
|
|
|||
|
RtlInitUnicodeString(&LinkName,wszDosDevices);
|
|||
|
p = (PWCHAR)LinkName.Buffer;
|
|||
|
p = p+12;
|
|||
|
for(i=0;i<26;i++){
|
|||
|
*p = (WCHAR)'A' + (WCHAR)i;
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&Obja,
|
|||
|
&LinkName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
Status = NtOpenSymbolicLinkObject(
|
|||
|
&LinkHandle,
|
|||
|
SYMBOLIC_LINK_QUERY,
|
|||
|
&Obja
|
|||
|
);
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
|
|||
|
//
|
|||
|
// Open succeeded, Now get the link value
|
|||
|
//
|
|||
|
DeviceName.Length = 0;
|
|||
|
DeviceName.MaximumLength = sizeof(DeviceNameBuffer);
|
|||
|
DeviceName.Buffer = DeviceNameBuffer;
|
|||
|
|
|||
|
Status = NtQuerySymbolicLinkObject(
|
|||
|
LinkHandle,
|
|||
|
&DeviceName,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtClose(LinkHandle);
|
|||
|
if ( NT_SUCCESS(Status) ) {
|
|||
|
|
|||
|
if (DeviceName.Buffer[(DeviceName.Length >>1) - 1] != *pSlash)
|
|||
|
RtlAppendUnicodeToString(&DeviceName, pSlash);
|
|||
|
|
|||
|
#ifdef JAPAN
|
|||
|
// #6197 compare only device name
|
|||
|
if (InputDeviceName->Length > DeviceName.Length)
|
|||
|
InputDeviceName->Length = DeviceName.Length;
|
|||
|
|
|||
|
#endif // JAPAN
|
|||
|
if ( RtlEqualUnicodeString(InputDeviceName,&DeviceName,TRUE) )
|
|||
|
{
|
|||
|
OutputDriveLetter[0]='A'+(WCHAR)i;
|
|||
|
OutputDriveLetter[1]='\0';
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// just in case we don't find it
|
|||
|
OutputDriveLetter[0]=(char)-1;
|
|||
|
OutputDriveLetter[1]='\0';
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* demSaveHardErrInfo
|
|||
|
* demRestoreHardErrInfo
|
|||
|
*
|
|||
|
* These two routines are used to preserve all the DOSKRNL registers
|
|||
|
* which will be needed to retry an SVC handler, in case user opts for
|
|||
|
* retry in harderr popup. This is a preferred way to handle retry
|
|||
|
* as it gives the DOSKRNL code the freedom to trash any register
|
|||
|
* even though it might have to retry the operation. It saves lots
|
|||
|
* of code bytes in heavily used DOS macro "HrdSVC".
|
|||
|
*
|
|||
|
* Entry
|
|||
|
* None
|
|||
|
*
|
|||
|
* Exit
|
|||
|
* None
|
|||
|
*
|
|||
|
* Notes
|
|||
|
*
|
|||
|
* 1. Doing things this way means, DOSKRNL cannot change the
|
|||
|
* registers for retry. Under any circumstances, i can't think
|
|||
|
* why it would need to do that anyway.
|
|||
|
*
|
|||
|
* 2. This mechanism also assumes that DOSKRNL never uses CS,IP,SS,SP
|
|||
|
* for passing SVC parameters.
|
|||
|
*
|
|||
|
* 3. DOS does'nt allow int24 hookers to make any call which comes
|
|||
|
* to DEM, so using CurrentISVC is safe.
|
|||
|
*
|
|||
|
* 4. If an SVC handler can pssibly return a hard error it should never
|
|||
|
* modify the client registers.
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
VOID demSaveHardErrInfo (VOID)
|
|||
|
{
|
|||
|
RetryInfo.ax = getAX();
|
|||
|
RetryInfo.bx = getBX();
|
|||
|
RetryInfo.cx = getCX();
|
|||
|
RetryInfo.dx = getDX();
|
|||
|
RetryInfo.ds = getDS();
|
|||
|
RetryInfo.es = getES();
|
|||
|
RetryInfo.si = getSI();
|
|||
|
RetryInfo.di = getDI();
|
|||
|
RetryInfo.bp = getBP();
|
|||
|
RetryInfo.iSVC = CurrentISVC;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID demRestoreHardErrInfo (VOID)
|
|||
|
{
|
|||
|
setAX(RetryInfo.ax);
|
|||
|
setBX(RetryInfo.bx);
|
|||
|
setCX(RetryInfo.cx);
|
|||
|
setDX(RetryInfo.dx);
|
|||
|
setDS(RetryInfo.ds);
|
|||
|
setES(RetryInfo.es);
|
|||
|
setSI(RetryInfo.si);
|
|||
|
setDI(RetryInfo.di);
|
|||
|
setBP(RetryInfo.bp);
|
|||
|
CurrentISVC = RetryInfo.iSVC;
|
|||
|
return;
|
|||
|
}
|
|||
|
|