620 lines
14 KiB
C
620 lines
14 KiB
C
/* demhndl.c - SVC handlers for calls where file handle is provided.
|
||
*
|
||
* demClose
|
||
* demRead
|
||
* demWrite
|
||
* demChgFilePtr
|
||
* demFileTimes
|
||
*
|
||
* Modification History:
|
||
*
|
||
* Sudeepb 02-Apr-1991 Created
|
||
* rfirth 25-Sep-1991 Added Vdm Redir stuff for named pipes
|
||
*/
|
||
|
||
#include "dem.h"
|
||
#include "demmsg.h"
|
||
|
||
#include <softpc.h>
|
||
#include <io.h>
|
||
#include <fcntl.h>
|
||
#include <vrnmpipe.h>
|
||
#include <exterr.h>
|
||
#include <mvdm.h>
|
||
|
||
BOOL (*VrInitialized)(VOID); // POINTER TO FUNCTION
|
||
extern BOOL IsVdmRedirLoaded(VOID);
|
||
|
||
/* demClose - Close a file
|
||
*
|
||
*
|
||
* Entry - Client (AX:BP) File Handle
|
||
* Client (CX:DX) File position (if -1 no seek needed before closing
|
||
* the handle.
|
||
* (VadimB)
|
||
* Client (es:di) SFT ptr - this is implied in abort.asm code
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client (CY) = 0
|
||
*
|
||
* FAILURE
|
||
* Client (CY) = 1
|
||
* Client (AX) = system status code
|
||
*
|
||
*/
|
||
|
||
VOID demClose (VOID)
|
||
{
|
||
HANDLE hFile;
|
||
LONG lLoc;
|
||
USHORT usDX,usCX;
|
||
|
||
hFile = GETHANDLE (getAX(),getBP());
|
||
|
||
if (hFile == 0) {
|
||
setCF (0);
|
||
return;
|
||
}
|
||
|
||
usCX = getCX();
|
||
usDX = getDX();
|
||
|
||
if (!((usCX == (USHORT)-1) && (usDX == (USHORT)-1))) {
|
||
lLoc = (LONG)((((int)usCX) << 16) + (int)usDX);
|
||
if (SetFilePointer (hFile,
|
||
lLoc,
|
||
NULL,
|
||
FILE_BEGIN) == -1L){
|
||
demClientError(hFile, (CHAR)-1);
|
||
return ;
|
||
}
|
||
|
||
}
|
||
|
||
if (CloseHandle (hFile) == FALSE){
|
||
demClientError(hFile, (CHAR)-1);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// if the redir TSR is being run in this VDM session, check if the handle
|
||
// being closed references a named pipe - we have to delete some info
|
||
// that we keep for the open named pipe
|
||
//
|
||
|
||
if (IsVdmRedirLoaded()) {
|
||
VrRemoveOpenNamedPipeInfo(hFile);
|
||
}
|
||
|
||
setCF(0);
|
||
return;
|
||
}
|
||
|
||
|
||
/* demRead - Read a file
|
||
*
|
||
*
|
||
* Entry - Client (AX:BP) File Handle
|
||
* Client (CX) Count to read
|
||
* Client (DS:DX) Buffer Address
|
||
* Client (BX:SI) = current file pointer location.
|
||
* ZF = 1 if seek is not needed prior to read.
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client (CY) = 0
|
||
* Client (AX) = Count of bytes read
|
||
*
|
||
* FAILURE
|
||
* Client (CY) = 1
|
||
* Client (AX) = system status code
|
||
*
|
||
*/
|
||
|
||
VOID demRead (VOID)
|
||
{
|
||
HANDLE hFile;
|
||
LPVOID lpBuf;
|
||
DWORD dwBytesRead;
|
||
USHORT usDS,usDX;
|
||
DWORD dwReadError;
|
||
BOOL ok;
|
||
UCHAR locus, action, class;
|
||
LONG lLoc;
|
||
|
||
hFile = GETHANDLE (getAX(),getBP());
|
||
usDS = getDS();
|
||
usDX = getDX();
|
||
lpBuf = (LPVOID) GetVDMAddr (usDS,usDX);
|
||
|
||
//
|
||
// if this handle is a named pipe then use VrReadNamedPipe since we have
|
||
// to perform an overlapped read, and wait on the event handle for completion
|
||
// even though we're still doing synchronous read
|
||
//
|
||
|
||
if (IsVdmRedirLoaded()) {
|
||
if (VrIsNamedPipeHandle(hFile)) {
|
||
|
||
//
|
||
// named pipe read always sets the extended error information in the
|
||
// DOS data segment. This is the only way we can return bytes read
|
||
// information and a more data indication
|
||
//
|
||
|
||
ok = VrReadNamedPipe(hFile,
|
||
lpBuf,
|
||
(DWORD)getCX(),
|
||
&dwBytesRead,
|
||
&dwReadError
|
||
);
|
||
switch (dwReadError) {
|
||
case NO_ERROR:
|
||
locus = action = class = 0;
|
||
break;
|
||
|
||
case ERROR_NO_DATA:
|
||
case ERROR_MORE_DATA:
|
||
locus = errLOC_Net;
|
||
class = errCLASS_TempSit;
|
||
action = errACT_Retry;
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// any error other than the specific ones we handle here should be
|
||
// correctly handled by DOS
|
||
//
|
||
|
||
goto readFailureExit;
|
||
}
|
||
pExtendedError->ExtendedErrorLocus = locus;
|
||
STOREWORD(pExtendedError->ExtendedError, (WORD)dwReadError);
|
||
pExtendedError->ExtendedErrorAction = action;
|
||
pExtendedError->ExtendedErrorClass = class;
|
||
if (ok) {
|
||
goto readSuccessExit;
|
||
} else {
|
||
goto readFailureExit;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// if the redir TSR is not loaded, or the handle is not a named pipe then
|
||
// perform normal file read
|
||
//
|
||
|
||
if (!getZF()) {
|
||
ULONG Zero = 0;
|
||
lLoc = (LONG)((((int)getBX()) << 16) + (int)getSI());
|
||
if ((SetFilePointer (hFile,
|
||
lLoc,
|
||
&Zero,
|
||
FILE_BEGIN) == -1L) &&
|
||
(GetLastError() != NO_ERROR)) {
|
||
goto readFailureExit;
|
||
}
|
||
|
||
}
|
||
|
||
if (ReadFile (hFile,
|
||
lpBuf,
|
||
(DWORD)getCX(),
|
||
&dwBytesRead,
|
||
NULL) == FALSE){
|
||
|
||
readFailureExit:
|
||
Sim32FlushVDMPointer (((ULONG)(usDS << 16)) | usDX, getCX(),
|
||
(PBYTE )lpBuf, FALSE);
|
||
Sim32FreeVDMPointer (((ULONG)(usDS << 16)) | usDX, getCX(),
|
||
(PBYTE )lpBuf, FALSE);
|
||
|
||
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
||
setAX(0);
|
||
setCF(0);
|
||
return;
|
||
}
|
||
demClientError(hFile, (CHAR)-1);
|
||
return ;
|
||
}
|
||
|
||
readSuccessExit:
|
||
Sim32FlushVDMPointer (((ULONG)(usDS << 16)) | usDX, getCX(),
|
||
(PBYTE )lpBuf, FALSE);
|
||
Sim32FreeVDMPointer (((ULONG)(usDS << 16)) | usDX, getCX(),
|
||
(PBYTE )lpBuf, FALSE);
|
||
setCF(0);
|
||
setAX((USHORT)dwBytesRead);
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
/* demWrite - Write to a file
|
||
*
|
||
*
|
||
* Entry - Client (AX:BP) File Handle
|
||
* Client (CX) Count to write
|
||
* Client (DS:DX) Buffer Address
|
||
* Client (BX:SI) = current file pointer location.
|
||
* ZF = 1 if seek is not needed prior to write.
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client (CY) = 0
|
||
* Client (AX) = Count of bytes written
|
||
*
|
||
* FAILURE
|
||
* Client (CY) = 1
|
||
* Client (AX) = system status code
|
||
*
|
||
*/
|
||
|
||
VOID demWrite (VOID)
|
||
{
|
||
HANDLE hFile;
|
||
DWORD dwBytesWritten;
|
||
LPVOID lpBuf;
|
||
LONG lLoc;
|
||
DWORD dwErrCode;
|
||
|
||
hFile = GETHANDLE (getAX(),getBP());
|
||
lpBuf = (LPVOID) GetVDMAddr (getDS(),getDX());
|
||
|
||
|
||
//
|
||
// if this handle is a named pipe then use VrWriteNamedPipe since we have
|
||
// to perform an overlapped write, and wait on the event handle for completion
|
||
// even though we're still doing synchronous write
|
||
//
|
||
|
||
if (IsVdmRedirLoaded()) {
|
||
if (VrIsNamedPipeHandle(hFile)) {
|
||
if (VrWriteNamedPipe(hFile, lpBuf, (DWORD)getCX(), &dwBytesWritten)) {
|
||
goto writeSuccessExit;
|
||
} else {
|
||
goto writeFailureExit;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// if the redir TSR is not loaded, or the handle is not a named pipe then
|
||
// perform normal file write
|
||
//
|
||
|
||
|
||
if (!getZF()) {
|
||
ULONG Zero = 0;
|
||
lLoc = (LONG)((((int)getBX()) << 16) + (int)getSI());
|
||
if ((SetFilePointer (hFile,
|
||
lLoc,
|
||
&Zero,
|
||
FILE_BEGIN) == -1L) &&
|
||
(GetLastError() != NO_ERROR)) {
|
||
demClientError(hFile, (CHAR)-1);
|
||
return ;
|
||
}
|
||
|
||
}
|
||
|
||
// In DOS CX=0 truncates or extends the file to current file pointer.
|
||
if (getCX() == 0){
|
||
if (SetEndOfFile(hFile) == FALSE){
|
||
demClientError(hFile, (CHAR)-1);
|
||
return;
|
||
}
|
||
setCF (0);
|
||
return;
|
||
}
|
||
|
||
if (WriteFile (hFile,
|
||
lpBuf,
|
||
(DWORD)getCX(),
|
||
&dwBytesWritten,
|
||
NULL) == FALSE){
|
||
|
||
// If disk is full then we should return 0 byte written and CF is clear
|
||
dwErrCode = GetLastError();
|
||
if(dwErrCode == ERROR_DISK_FULL) {
|
||
|
||
setCF(0);
|
||
setAX(0);
|
||
return;
|
||
}
|
||
|
||
SetLastError(dwErrCode);
|
||
|
||
writeFailureExit:
|
||
demClientError(hFile, (CHAR)-1);
|
||
return ;
|
||
}
|
||
|
||
writeSuccessExit:
|
||
setCF(0);
|
||
setAX((USHORT)dwBytesWritten);
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
/* demChgFilePtr - Change File Pointer
|
||
*
|
||
*
|
||
* Entry - Client (AX:BP) File Handle
|
||
* Client (CX:DX) New Location
|
||
* Client (BL) Positioning Method
|
||
* 0 - File Absolute
|
||
* 1 - Relative to Current Position
|
||
* 2 - Relative to end of file
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client (CY) = 0
|
||
* Client (DX:AX) = New Location
|
||
*
|
||
* FAILURE
|
||
* Client (CY) = 1
|
||
* Client (AX) = system status code
|
||
*
|
||
*/
|
||
|
||
VOID demChgFilePtr (VOID)
|
||
{
|
||
HANDLE hFile;
|
||
LONG lLoc;
|
||
DWORD dwLoc;
|
||
|
||
#if (FILE_BEGIN != 0 || FILE_CURRENT != 1 || FILE_END !=2)
|
||
#error "Win32 values not DOS compatible"
|
||
#
|
||
|
||
#endif
|
||
hFile = GETHANDLE (getAX(),getBP());
|
||
lLoc = (LONG)((((int)getCX()) << 16) + (int)getDX());
|
||
|
||
if ((dwLoc = SetFilePointer (hFile,
|
||
lLoc,
|
||
NULL,
|
||
(DWORD)getBL())) == -1L){
|
||
demClientError(hFile, (CHAR)-1);
|
||
return ;
|
||
}
|
||
|
||
setCF(0);
|
||
setAX((USHORT)dwLoc);
|
||
setDX((USHORT)(dwLoc >> 16));
|
||
return;
|
||
}
|
||
|
||
|
||
#if 0
|
||
|
||
/*
|
||
* Completely moved to demlfn.c
|
||
*
|
||
*
|
||
*
|
||
*/
|
||
|
||
/* demFileTimes - Change or Get File date and times
|
||
*
|
||
* GET TIME (Client(BL) = 0)
|
||
*
|
||
* Entry
|
||
* Client(AX:BP)
|
||
* NT Handle
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client(CF) = 0
|
||
* Client(CX) = File time
|
||
* Client(DX) = File date
|
||
* FAILURE
|
||
* Client(CF) = 1
|
||
* Client(AX) = error code
|
||
*
|
||
* SET TIME (Client(BL) = 1)
|
||
*
|
||
* Entry
|
||
* Client(AX:BP)
|
||
* Nt Handle
|
||
* Client(CX)
|
||
* New file time
|
||
* Client(DX)
|
||
* New file date
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client(CF) = 0
|
||
* FAILURE
|
||
* Client(CF) = 1
|
||
* Client(AX) = error code
|
||
*
|
||
* Hard Error Exit
|
||
* Client(CF) = 1
|
||
* Client(AX) = 0FFFFh
|
||
*
|
||
* GET TIME For device (Client(BL) = 2)
|
||
*
|
||
* Entry
|
||
* Client(AX:BP)
|
||
* NT Handle - not in use
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client(CF) = 0
|
||
* Client(CX) = Current time
|
||
* Client(DX) = Curren date
|
||
* FAILURE
|
||
* None
|
||
*
|
||
*/
|
||
|
||
VOID demFileTimes (VOID)
|
||
{
|
||
HANDLE hFile;
|
||
WORD wDate,wTime;
|
||
FILETIME LastWriteTime,ftTemp;
|
||
SYSTEMTIME stCurrentTime;
|
||
UCHAR uchOpt = 0;
|
||
|
||
uchOpt = getBL();
|
||
if(uchOpt != 2)
|
||
hFile = GETHANDLE(getAX(),getBP());
|
||
|
||
if(uchOpt != 1){
|
||
|
||
if(!uchOpt) {
|
||
if(GetFileTime (hFile,NULL,NULL,&LastWriteTime) == -1){
|
||
demClientError(hFile, (CHAR)-1);
|
||
return;
|
||
}
|
||
}
|
||
else { // Device case. We should return current time
|
||
GetSystemTime(&stCurrentTime);
|
||
SystemTimeToFileTime(&stCurrentTime, &LastWriteTime);
|
||
|
||
}
|
||
|
||
FileTimeToLocalFileTime (&LastWriteTime,&ftTemp);
|
||
if(FileTimeToDosDateTime(&ftTemp,
|
||
(LPWORD)&wDate,
|
||
(LPWORD)&wTime) == FALSE){
|
||
demPrintMsg(MSG_TIMEDATE);
|
||
setCF(0);
|
||
return;
|
||
}
|
||
|
||
setCX(wTime);
|
||
setDX(wDate);
|
||
setCF(0);
|
||
return;
|
||
}
|
||
|
||
wDate = getDX();
|
||
wTime = getCX();
|
||
|
||
if (DosDateTimeToFileTime(wDate,
|
||
wTime,
|
||
&LastWriteTime) == FALSE){
|
||
demPrintMsg(MSG_TIMEDATE);
|
||
setCF(0);
|
||
return;
|
||
}
|
||
LocalFileTimeToFileTime (&LastWriteTime,&ftTemp);
|
||
|
||
if(!SetFileTime(hFile,NULL,NULL,&ftTemp)){
|
||
demClientError(hFile, (CHAR)-1);
|
||
return;
|
||
}
|
||
|
||
setCF(0);
|
||
return;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/* DemCommit -- Commit File(Flush file buffers)
|
||
*
|
||
* Entry - Client (AX:BP) File Handle
|
||
*
|
||
* Exit
|
||
* SUCCESS
|
||
* Client (CY) = 0
|
||
* buffer flushed
|
||
*
|
||
* FAILURE
|
||
* Client (CY) = 1
|
||
*
|
||
*/
|
||
VOID demCommit(VOID)
|
||
{
|
||
HANDLE hFile;
|
||
BOOL bRet;
|
||
|
||
hFile = GETHANDLE(getAX(),getBP());
|
||
bRet = FlushFileBuffers(hFile);
|
||
#if DBG
|
||
if (!bRet) {
|
||
|
||
//
|
||
// FlushFileBuffers fails with access denied if the handle
|
||
// is open for read-only access, however it's not an error
|
||
// for DOS.
|
||
//
|
||
|
||
DWORD LastError;
|
||
LastError = GetLastError();
|
||
|
||
if (LastError != ERROR_ACCESS_DENIED) {
|
||
sprintf(demDebugBuffer,
|
||
"ntvdm demCommit warning: FlushFileBuffers error %d\n",
|
||
LastError);
|
||
OutputDebugStringOem(demDebugBuffer);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
setCF(0);
|
||
|
||
}
|
||
|
||
/* function to check if new data has been written to the file or
|
||
if the file has been marked EOF
|
||
|
||
Input: Client (AX:BP) = 32bits NT file handle
|
||
Output: Client ZF = 1 if new data or EOF
|
||
CF = 1 if EOF
|
||
*/
|
||
|
||
|
||
VOID demPipeFileDataEOF(VOID)
|
||
{
|
||
HANDLE hFile;
|
||
BOOL fEOF;
|
||
BOOL DataEOF;
|
||
DWORD FileSizeLow;
|
||
DWORD FileSizeHigh;
|
||
|
||
hFile = GETHANDLE(getAX(), getBP());
|
||
|
||
DataEOF = cmdPipeFileDataEOF(hFile, &fEOF);
|
||
if (fEOF) {
|
||
//EOF, get file size, max size = 32bits
|
||
FileSizeLow = GetFileSize(hFile, &FileSizeHigh);
|
||
setAX((WORD)(FileSizeLow / 0x10000));
|
||
setBP((WORD)FileSizeLow);
|
||
setCF(1); // EOF is encountered
|
||
}
|
||
else
|
||
setCF(0);
|
||
setZF(DataEOF ? 0 : 1);
|
||
}
|
||
|
||
/* function to check if the file has been marked EOF
|
||
Input: Client(AX:BP) = 32bits NT file handle
|
||
Output: Client CY = 1 if EOF
|
||
*/
|
||
|
||
VOID demPipeFileEOF(VOID)
|
||
{
|
||
HANDLE hFile;
|
||
DWORD FileSizeLow;
|
||
DWORD FileSizeHigh;
|
||
|
||
hFile = GETHANDLE(getAX(), getBP());
|
||
if (cmdPipeFileEOF(hFile)) {
|
||
FileSizeLow = GetFileSize(hFile, &FileSizeHigh);
|
||
setAX((WORD)(FileSizeLow / 0x10000)); // file size in 32bits
|
||
setBP((WORD)FileSizeLow);
|
||
setCF(1); //EOF is encountered
|
||
}
|
||
else
|
||
setCF(0);
|
||
}
|
||
|