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;
|
||
}
|
||
|