diff options
Diffstat (limited to '')
-rw-r--r-- | private/mvdm/dos/dem/dem.c | 76 | ||||
-rw-r--r-- | private/mvdm/dos/dem/dem.h | 260 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demdasd.c | 734 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demdasd.h | 301 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demdata.c | 24 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demdir.c | 182 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demdisp.c | 245 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demerror.c | 388 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demfcb.c | 768 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demfile.c | 1160 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demgset.c | 1013 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demhndl.c | 605 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demioctl.c | 583 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demlabel.c | 76 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demlock.c | 62 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demmisc.c | 644 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demmsg.c | 48 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demmsg.h | 18 | ||||
-rw-r--r-- | private/mvdm/dos/dem/demsrch.c | 2442 | ||||
-rw-r--r-- | private/mvdm/dos/dem/dosdef.h | 140 | ||||
-rw-r--r-- | private/mvdm/dos/dem/makefile | 9 | ||||
-rw-r--r-- | private/mvdm/dos/dem/sources | 65 |
22 files changed, 9843 insertions, 0 deletions
diff --git a/private/mvdm/dos/dem/dem.c b/private/mvdm/dos/dem/dem.c new file mode 100644 index 000000000..b8b46868e --- /dev/null +++ b/private/mvdm/dos/dem/dem.c @@ -0,0 +1,76 @@ +/* + * dem.c - Main Module of DOS Emulation DLL. + * + * Sudeepb 09-Apr-1991 Craeted + */ + +#include "io.h" +#include "dem.h" + +/* DemInit - DEM Initialiazation routine. (This name may change when DEM is + * converted to DLL). + * + * Entry + * argc,argv - from softpc as it is. + * + * + * Exit + * None + */ + +PSZ pszDefaultDOSDirectory; + +extern VOID TerminateVDM(VOID); + +CHAR demDebugBuffer [256]; + +#if DBG +BOOL ToDebugOnF11 = FALSE; +#endif + +BOOL DemInit (int argc, char *argv[]) +{ + PSZ psz; + DWORD dw; + + // Modify default hard error handling + // - turn off all file io related popups + // - keep GP fault popups from system + // + SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + pszDefaultDOSDirectory = (PCHAR) malloc(MAX_PATH+14); + if (!pszDefaultDOSDirectory || + !(dw = GetSystemDirectory(pszDefaultDOSDirectory, MAX_PATH)) || + dw >= MAX_PATH ) + { + return FALSE; + } + + if (VDMForWOW) + return TRUE; + + // Check the debugging level + while (--argc > 0) { + psz = *++argv; + if (*psz == '-' || *psz == '/') { + psz++; + if(tolower(*psz) == 'd'){ + fShowSVCMsg = DEMDOSDISP | DEMFILIO; + break; + } + } + } + + +#if DBG +#ifndef i386 + if( getenv( "YODA" ) != 0 ) +#else + if( getenv( "DEBUGDOS" ) != 0 ) +#endif + ToDebugOnF11 = TRUE; +#endif + + return TRUE; +} diff --git a/private/mvdm/dos/dem/dem.h b/private/mvdm/dos/dem/dem.h new file mode 100644 index 000000000..9b1276b7f --- /dev/null +++ b/private/mvdm/dos/dem/dem.h @@ -0,0 +1,260 @@ +/* dem.h - main include file for dem + * + * Modification History + * + * Sudeepb 31-Mar-1991 Created + */ + +#ifndef _DEMINCLUDED_ +#define _DEMINCLUDED_ + +/* +#define WIN +#define FLAT_32 +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> + +#define _WINDOWS +#include <windows.h> + +*/ + +#ifdef DOS +#define SIGNALS +#endif + +#ifdef OS2_16 +#define OS2 +#define SIGNALS +#endif + +#ifdef OS2_32 +#define OS2 +#define FLAT_32 +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <malloc.h> +#include <process.h> + +#ifdef WIN_16 +#define WIN +#define API16 +#endif + +#ifdef WIN_32 +#define WIN +#define FLAT_32 +#define TRUE_IF_WIN32 1 +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntdddisk.h> +#else +#define TRUE_IF_WIN32 0 +#endif + +#ifdef FLAT_32 +#ifndef i386 +#define ALIGN_32 +#else +#define NOALIGN_32 +#endif +#endif + +#ifdef WIN +#define _WINDOWS +#include <windows.h> +#endif + +#ifdef SIGNALS +#include <conio.h> +#include <signal.h> +#endif + +#ifdef OS2_32 +#include <excpt.h> +#define XCPT_SIGNAL 0xC0010003 +#endif +#define SIGHIT(flChk) ((iSigCheck++ & 0x7FF)?(flSignals & (flChk)):(kbhit(),(flSignals & (flChk)))) + +#include <oemuni.h> + + + + +/** Basic Typedefs of DEM **/ + +typedef VOID (*PFNSVC)(VOID); + +typedef struct _SAVEDEMWORLD { + USHORT ax; + USHORT bx; + USHORT cx; + USHORT dx; + USHORT ds; + USHORT es; + USHORT si; + USHORT di; + USHORT bp; + ULONG iSVC; +} SAVEDEMWORLD, *PSAVEDEMWORLD; + + +typedef struct _DISKINFO { + WORD wSectorsPerCluster; + WORD wBytesPerSector; + WORD wFreeClusters; + WORD wTotalClusters; +} DISKINFO, *PDISKINFO; + +#include "dosdef.h" +#include "dossvc.h" + + + +/** DEM Externs **/ + +extern ULONG UNALIGNED *pulDTALocation; +extern BOOL VDMForWOW; +extern PVHE pHardErrPacket; +extern ULONG CurrentISVC; +extern PCHAR aSVCNames[]; +extern PFNSVC apfnSVC[]; +extern PSZ pszDefaultDOSDirectory; +extern USHORT nDrives; +extern PUSHORT pusCurrentPDB; +extern PDEMEXTERR pExtendedError; + + +#include "demexp.h" +#if DEVL +extern CHAR demDebugBuffer []; +#endif + + + + +/** DEM Macros **/ + +#define GETULONG(hi,lo) (DWORD)((((int) hi) << 16) + ((int) lo)) +#define GETHANDLE(hi,lo) (HANDLE)(GETULONG(hi,lo)) +#define IS_ASCII_PATH_SEPARATOR(ch) (((ch) == '/') || ((ch) == '\\')) + + +/** Function Prototypes */ + +VOID demChgFilePtr (VOID); +VOID demChMod (VOID); +VOID demClose (VOID); +VOID demCloseFCB (VOID); +VOID demCreate (VOID); +VOID demCreateFCB (VOID); +VOID demCreateDir (VOID); +VOID demCreateNew (VOID); +VOID demDate16 (VOID); +VOID demDelete (VOID); +VOID demDeleteDir (VOID); +VOID demDeleteFCB (VOID); +VOID demFCBIO (VOID); +VOID demFileTimes (VOID); +VOID demFindFirst (VOID); +VOID demFindFirstFCB (VOID); +VOID demFindNext (VOID); +VOID demFindNextFCB (VOID); +VOID demGetBootDrive (VOID); +VOID demGetDriveFreeSpace (VOID); +VOID demGetDrives (VOID); +VOID demGetFileInfo (VOID); +VOID demGSetMediaID (VOID); +VOID demIOCTL (VOID); +VOID demLoadDos (VOID); +VOID demLockOper (VOID); +VOID demOpen (VOID); +VOID demOpenFCB (VOID); +VOID demQueryCurrentDir (VOID); +VOID demQueryDate (VOID); +VOID demQueryTime (VOID); +VOID demRead (VOID); +VOID demRename (VOID); +VOID demRenameFCB (VOID); +VOID demRetry (VOID); +VOID demSetCurrentDir (VOID); +VOID demSetDate (VOID); +VOID demSetDefaultDrive (VOID); +VOID demSetDTALocation (VOID); +VOID demSetHardErrorInfo(VOID); +VOID demSetTime (VOID); +VOID demSetV86KernelAddr(VOID); +VOID demWrite (VOID); +VOID demGetDriveInfo (VOID); +VOID demDiskReset (VOID); +VOID demLoadDosAppSym (VOID); +VOID demFreeDosAppSym (VOID); +VOID demEntryDosApp (VOID); +VOID demDOSDispCall (VOID); +VOID demDOSDispRet (VOID); +VOID demOutputString (VOID); +VOID demInputString (VOID); +VOID demIsDebug (VOID); +VOID demTerminatePDB (VOID); +VOID demExitVDM (VOID); +VOID demWOWFiles (VOID); +VOID demGetComputerName (VOID); +VOID demCheckPath (VOID); +VOID demSystemSymbolOp (VOID); +VOID demCommit (VOID); +VOID demClientError (HANDLE,CHAR); +ULONG demClientErrorEx (HANDLE,CHAR,BOOL); +VOID demCreateCommon (ULONG); +BOOL demGetMiscInfo (HANDLE, LPWORD, LPWORD, LPDWORD); +VOID demFCBCommon (ULONG); + +VOID demIoctlChangeable (VOID); +VOID demIoctlInvalid (VOID); +VOID demSaveHardErrInfo (VOID); +VOID demRestoreHardErrInfo (VOID); +VOID demAbsRead (VOID); +VOID demAbsWrite (VOID); +VOID demIoctlDiskGeneric (VOID); +VOID demIoctlDiskQuery (VOID); +VOID demGetDPB (VOID); +VOID demGetDPBList (VOID); +VOID demNotYetImplemented (VOID); +BOOL GetDiskSpaceInformation(CHAR chDrive, PDISKINFO pDiskInfo); +BOOL demGetDiskFreeSpace(BYTE Drive, WORD * BytesPerSector, + WORD * SectorsPerCluster, WORD * TotalClusters, + WORD * FreeClusters); +BOOL IsCdRomFile (PSTR pszPath); + +BOOL GetMediaId( CHAR DriveNum, PVOLINFO pVolInfo); +VOID demPipeFileDataEOF (VOID); +VOID demPipeFileEOF (VOID); + +/** Debug Function Prototypes */ + +#if DBG + +VOID demPrintMsg (ULONG iMsg); + +#else + +#define demPrintMsg(x) + +#endif + +/* Label functions and constants */ +USHORT demDeleteLabel(BYTE Drive); +USHORT demCreateLabel(BYTE Drive, LPSTR szName); +#define DRIVEBYTE 0 +#define LABELOFF 3 + +extern BOOL cmdPipeFileDataEOF (HANDLE,BOOL *); +extern BOOL cmdPipeFileEOF(HANDLE); + + +#endif /* _DEMINCLUDED_ */ diff --git a/private/mvdm/dos/dem/demdasd.c b/private/mvdm/dos/dem/demdasd.c new file mode 100644 index 000000000..0afa89204 --- /dev/null +++ b/private/mvdm/dos/dem/demdasd.c @@ -0,0 +1,734 @@ + +/* + * demdasd.c - module for direct disk access related support functions + * + * Williamh 09-Dec-1992 Created + * Revision 24-Mar-1993 added fdisk support + */ + +#include "io.h" +#include "dem.h" +#include "stdio.h" +#include "windows.h" +#include "demdasd.h" +#include "softpc.h" + +PBDS demBDS; +BYTE NumberOfFloppy; +BYTE NumberOfFdisk; + +extern WORD int13h_vector_off, int13h_vector_seg; +extern WORD int13h_caller_off, int13h_caller_seg; + +BPB StdBpb[MAX_FLOPPY_TYPE] = { + {512, 2, 1, 2, 112, 2*9*40, 0xFD, 2, 9, 2, 0, 0}, // 360KB + {512, 1, 1, 2, 224, 2*15*80, 0xF9, 7, 15, 2, 0, 0}, // 1.2MB + {512, 2, 1, 2, 112, 2*9*80, 0xF9, 3, 9, 2, 0, 0}, // 720KB + {512, 1, 1, 2, 224, 2*18*80, 0xF0, 9, 18, 2, 0, 0}, // 1.44MB + {512, 2, 1, 2, 240, 2*36*80, 0xF0, 9, 36, 2, 0, 0} // 2.88MB + }; + +BYTE FormFactorTable[MAX_FLOPPY_TYPE] = { + FF_360, + FF_120, + FF_720, + FF_144, + FF_288 + }; + +/* demDasdInit - dem diskette system Initialiazation + * + * Entry + * none + * + * + * Exit + * None + */ +VOID demDasdInit(VOID) +{ + demBDS = NULL; + NumberOfFloppy = NumberOfFdisk = 0; + demFloppyInit(); + demFdiskInit(); +} +/* demAbsRead - int 25, absolute read + * + * Entry + * Client (AL) = drive number (0 based) + * (DS:BX) = pointer to the buffer to receive the read data + * or pointer to the DISKIO structure + * (CX) = number of sectors to read + * if (0FFFFh) then DS:DX points to DISKIO + * DX contents are discarded + * (DX) = starting sector number + * + * + * Exit + * Client (CY) = 0 if operation succeed + * (AX) = 0 + * + * (CY) = 1 if operation failed + * (AX) = error code + */ + +VOID demAbsRead (VOID) +{ +#if DBG + if (fShowSVCMsg & DEM_ABSDRD) + OutputDebugStringOem("DEM: INT 25 Called \n"); +#endif + demAbsReadWrite(FALSE); +} + + + + +/* demAbsWrite - int 26, absolute read + * + * + * Entry + * Client (AL) = drive number (0 based) + * (DS:BX) = pointer to the buffer to receive the read data + * or pointer to the DISKIO structure + * (CX) = number of sectors to read + * if (0FFFFh) then DS:DX points to DISKIO + * DX contents are discarded + * (DX) = starting sector number + * + * + * Exit + * Client (CY) = 0 if operation succeed + * (AX) = 0 + * + * (CY) = 1 if operation failed + * (AX) = error code + */ + +VOID demAbsWrite(VOID) +{ +#if DBG + if (fShowSVCMsg & DEM_ABSWRT) + OutputDebugStringOem("DEM: INT 26 Called \n"); +#endif + demAbsReadWrite(TRUE); +} + + + +VOID demAbsReadWrite(BOOL IsWrite) +{ + BYTE Drive; + DWORD LastError; + DWORD Sectors; + DWORD StartSector; + PDISKIO DiskIo; + DWORD SectorsReturned; + PBDS pBDS; + WORD BufferOff, BufferSeg; + + Drive = getAL(); + if ((Sectors = getCX()) == 0xFFFF) { + DiskIo = (PDISKIO) GetVDMAddr(getDS(), getBX()); + Sectors = DiskIo->Sectors; + StartSector = DiskIo->StartSector; + BufferOff = DiskIo->BufferOff; + BufferSeg = DiskIo->BufferSeg; + } + else { + StartSector = getDX(); + BufferOff = getBX(); + BufferSeg = getDS(); + } + if ((pBDS = demGetBDS(Drive)) == NULL) { + if (!demIsDriveFloppy(Drive)) + host_direct_access_error(NOSUPPORT_HARDDISK); + setAX(DOS_DRIVE_NOT_READY); + setCF(1); + return; + } +#if DBG + if (fShowSVCMsg & (DEM_ABSDRD | DEM_ABSWRT)) { + sprintf(demDebugBuffer, "Drive Number: %d\n", Drive); + OutputDebugStringOem(demDebugBuffer); + sprintf(demDebugBuffer, "StartSector: %d\n", StartSector); + OutputDebugStringOem(demDebugBuffer); + sprintf(demDebugBuffer, "Total Sectors: %d\n", Sectors); + OutputDebugStringOem(demDebugBuffer); + sprintf(demDebugBuffer, "Buffer: %x:%x\n", BufferSeg, BufferOff); + } +#endif + + if (IsWrite) + SectorsReturned = demDasdWrite(pBDS, + StartSector, + Sectors, + BufferOff, + BufferSeg + ); + else + SectorsReturned = demDasdRead(pBDS, + StartSector, + Sectors, + BufferOff, + BufferSeg + ); + if (SectorsReturned != Sectors) { + LastError = GetLastError(); +#if DBG + if (fShowSVCMsg & (DEM_ABSDRD | DEM_ABSWRT)) { + sprintf(demDebugBuffer, "dem: AbsRDWR Failed, error=%lx\n", LastError); + OutputDebugStringOem(demDebugBuffer); + } +#endif + setAX(demWinErrorToDosError(LastError)); + setCF(1); + return; + } + setCF(0); + return; +} + +DWORD demDasdRead( + PBDS pbds, + DWORD StartSector, + DWORD Sectors, + WORD BufferOff, + WORD BufferSeg +) + +{ + + ULONG SizeReturned; + LARGE_INTEGER LargeInteger; + DWORD Size; + DWORD SectorSize; + WORD CurBiosDiskIoOff, CurBiosDiskIoSeg; + PBYTE Buffer; + + // if this is the first time we access the BDS or + // the media has been changed, build the bds -- floppy + if (!(pbds->Flags & NON_REMOVABLE) && + ((pbds->Flags & UNFORMATTED_MEDIA) || + !nt_floppy_media_check(pbds->DrivePhys))) { + if (!demGetBPB(pbds)) + return 0; + } + if (StartSector >= pbds->TotalSectors || + StartSector + Sectors > pbds->TotalSectors) { + SetLastError(ERROR_SECTOR_NOT_FOUND); + return 0 ; + } + SectorSize = pbds->bpb.SectorSize; + LargeInteger.QuadPart = Int32x32To64(Sectors, SectorSize); + // size must fit in ulong + if (LargeInteger.HighPart != 0) { + SetLastError(ERROR_SECTOR_NOT_FOUND); + return 0; + } + Size = LargeInteger.LowPart; + + Buffer = (PBYTE) GetVDMAddr(BufferSeg, BufferOff); + + if (pbds->Flags & NON_REMOVABLE) { + LargeInteger.QuadPart = Int32x32To64(StartSector, SectorSize); + SizeReturned = nt_fdisk_read( + pbds->DrivePhys, + &LargeInteger, + Size, + Buffer + ); + } + else { + // floppy need special care beacuse application may hook + // bios disk interrupt. We dont' do this for hard disks because + // we don't allow int13 to them + sas_loadw(0x13*4, &CurBiosDiskIoOff); + sas_loadw(0x13* 4 + 2, &CurBiosDiskIoSeg); + if (int13h_vector_off == CurBiosDiskIoOff && + int13h_vector_seg == CurBiosDiskIoSeg) + SizeReturned = nt_floppy_read( + pbds->DrivePhys, + StartSector * SectorSize, + Size, + Buffer + ); + else + return (demBiosDiskIoRW(pbds, + StartSector, + Sectors, + BufferOff, + BufferSeg, + FALSE + )); + } + if (SizeReturned == Size) + return Sectors; + else + return SizeReturned / SectorSize; + +} + +DWORD demDasdWrite( + PBDS pbds, + DWORD StartSector, + DWORD Sectors, + WORD BufferOff, + WORD BufferSeg +) + + +{ + ULONG SizeReturned; + LARGE_INTEGER LargeInteger; + DWORD Size; + DWORD SectorSize; + WORD CurBiosDiskIoOff, CurBiosDiskIoSeg; + PBYTE Buffer; + + // if this is the first time we access the BDS or + // the media has been changed, build the bds + if (!(pbds->Flags & NON_REMOVABLE) && + ((pbds->Flags & UNFORMATTED_MEDIA) || + !nt_floppy_media_check(pbds->DrivePhys))) { + if (!demGetBPB(pbds)) + return 0; + } + if (StartSector >= pbds->TotalSectors || + StartSector + Sectors > pbds->TotalSectors) { + SetLastError(ERROR_SECTOR_NOT_FOUND); + return 0 ; + } + SectorSize = pbds->bpb.SectorSize; + LargeInteger.QuadPart = Int32x32To64(Sectors, SectorSize); + // size must fit in ulong + if (LargeInteger.HighPart != 0) { + SetLastError(ERROR_SECTOR_NOT_FOUND); + return 0; + } + Size = LargeInteger.LowPart; + Buffer = (PBYTE) GetVDMAddr(BufferSeg, BufferOff); + + + if (pbds->Flags & NON_REMOVABLE) { + LargeInteger.QuadPart = Int32x32To64(StartSector, SectorSize); + SizeReturned = nt_fdisk_write( + pbds->DrivePhys, + &LargeInteger, + Size, + Buffer + ); + } + else { + // floppy need special care beacuse application may hook + // bios disk interrupt. We dont' do this for hard disks because + // we don't allow int13 to them + sas_loadw(0x13*4, &CurBiosDiskIoOff); + sas_loadw(0x13* 4 + 2, &CurBiosDiskIoSeg); + if (int13h_vector_off == CurBiosDiskIoOff && + int13h_vector_seg == CurBiosDiskIoSeg) + SizeReturned = nt_floppy_write( + pbds->DrivePhys, + StartSector * SectorSize, + Size, + Buffer + ); + else + return(demBiosDiskIoRW(pbds, + StartSector, + Sectors, + BufferOff, + BufferSeg, + TRUE + )); + } + + if (Size == SizeReturned) + return Sectors; + else + return SizeReturned / SectorSize; + + +} + +BOOL demDasdFormat(PBDS pbds, DWORD Head, DWORD Cylinder, MEDIA_TYPE * Media) +{ + BOOL Result; + + if (pbds->Flags & NON_REMOVABLE) + Result = demDasdVerify(pbds, Head, Cylinder); + else { + + if (*Media == Unknown) { + *Media = nt_floppy_get_media_type(pbds->DrivePhys, + pbds->Cylinders, + pbds->bpb.TrackSize, + pbds->bpb.Heads + ); + return TRUE; + } + else { + Result = nt_floppy_format(pbds->DrivePhys, + (WORD)Cylinder, + (WORD)Head, + *Media + ); + } + } + return (Result); +} + + +BOOL demDasdVerify(PBDS pbds, DWORD Head, DWORD Cylinder) +{ + DWORD Size, StartSector; + LARGE_INTEGER LargeInteger; + + // if floppy, make sure we have up-to-date BPB and a valid media is in + if (!(pbds->Flags & NON_REMOVABLE)) { + if (!demGetBPB(pbds)) + return FALSE; + Size = pbds->bpb.TrackSize * pbds->bpb.SectorSize; + StartSector = pbds->bpb.TrackSize * (Cylinder * pbds->bpb.Heads + Head) + 1; + return (nt_floppy_verify(pbds->DrivePhys, + StartSector * pbds->bpb.SectorSize, + Size)); + } + // hard disk needs special care because of their size + Size = pbds->bpb.TrackSize * pbds->bpb.SectorSize; + StartSector = pbds->bpb.TrackSize * (Cylinder * pbds->bpb.Heads + Head) + 1; + LargeInteger.QuadPart = Int32x32To64(StartSector, pbds->bpb.SectorSize); + return (nt_fdisk_verify(pbds->DrivePhys, + &LargeInteger, + Size + )); +} + +PBDS demGetBDS(BYTE DriveLog) +{ + PBDS pbds; + pbds = demBDS; + while (pbds != NULL && pbds->DriveLog != DriveLog) + pbds = pbds->Next; + return pbds; +} + +BOOL demGetBPB(PBDS pbds) +{ + PBOOTSECTOR pbs; + BYTE SectorBuffer[BYTES_PER_SECTOR]; + + // when RETURN_FAKE_BPB is set(set by Set Device Parameter IOCTL, + // the appplication has set a new BPB, we simply return it + if (!(pbds->Flags & RETURN_FAKE_BPB) && + !(pbds->Flags & NON_REMOVABLE) && + ((pbds->Flags & UNFORMATTED_MEDIA) || !nt_floppy_media_check(pbds->DrivePhys)) + ) { + pbds->Flags &= ~(UNFORMATTED_MEDIA); + nt_floppy_close(pbds->DrivePhys); + if (nt_floppy_read(pbds->DrivePhys, + 0, + BYTES_PER_SECTOR, + SectorBuffer + ) != BYTES_PER_SECTOR) + return FALSE; + pbs = (PBOOTSECTOR)SectorBuffer; + if ((pbs->Jump == 0x69 || pbs->Jump == 0xE9 || + (pbs->Jump == 0xEB && pbs->Target[1] == 0x90)) && + (pbs->bpb.MediaID & 0xF0) == 0xF0) { + pbds->bpb = pbs->bpb; + pbds->TotalSectors = (pbs->bpb.Sectors) ? pbs->bpb.Sectors : + pbs->bpb.BigSectors; + return TRUE; + } + // an unknown media found + else { + pbds->Flags |= UNFORMATTED_MEDIA; + // What should we do here? The diskette has strange boot sector + // should we guess it or what? + // +#if DEVL + if (fShowSVCMsg & (DEM_ABSDRD | DEM_ABSWRT)) { + sprintf(demDebugBuffer, "Invalid Boot Sector Found\n"); + OutputDebugStringOem(demDebugBuffer); + } +#endif + host_direct_access_error(NOSUPPORT_FLOPPY); + return FALSE; + } + } + return TRUE; +} + +DWORD demBiosDiskIoRW( + PBDS pbds, + DWORD StartSector, + DWORD Sectors, + WORD BufferOff, + WORD BufferSeg, + BOOL IsWrite +) +{ + BYTE CurHead, CurSector, BiosErrorCode; + WORD CurTrack, TrackSize, Heads, SectorTrack; + WORD AX, BX, CX, DX, ES, CS, IP; + BYTE SectorsRead, SectorsToRead; + WORD wRetry = 3; + + AX = getAX(); + BX = getBX(); + CX = getCX(); + DX = getDX(); + ES = getES(); + CS = getCS(); + IP = getIP(); + + TrackSize = pbds->bpb.TrackSize; + Heads = pbds->bpb.Heads; + SectorsRead = 0; + CurSector = (BYTE) ((StartSector % TrackSize) + 1); + CurTrack = (WORD) (StartSector / TrackSize); + CurHead = CurTrack % Heads; + CurTrack /= Heads; + SectorsToRead = TrackSize - CurSector + 1; + while (Sectors != 0) { + if (Sectors < SectorsToRead) + SectorsToRead = (BYTE) Sectors; + // low byte: bit 6 and 7 are high bits of track, + // bit 0 - 5 are sector number + // high byte: bit 0 - bit 7 ->track lower 8 bits + SectorTrack = ((CurTrack & 0x300) >> 2) | (CurSector & 0x3f) | + ((CurTrack &0xFF) << 8); + wRetry = 3; +BiosRetry: + setAH((BYTE) ((IsWrite) ? DISKIO_WRITE : DISKIO_READ)); + setAL(SectorsToRead); + setBX(BufferOff); + setES(BufferSeg); + setDH(CurHead); + setDL(pbds->DrivePhys); + setCX(SectorTrack); + setCS(int13h_caller_seg); + setIP(int13h_caller_off); + host_simulate(); + if (getCF() == 0) { + SectorsRead += SectorsToRead; + if ((Sectors -= SectorsToRead) == 0) + break; + CurSector = 1; + if (++CurHead == Heads) { + CurHead = 0; + CurTrack++; + } + SectorsToRead = (BYTE) TrackSize; + } + else { + BiosErrorCode = getAH(); + // reset the disk + setAH(DISKIO_RESET); + setDL(pbds->DrivePhys); + setCS(int13h_caller_seg); + setIP(int13h_caller_off); + host_simulate(); + // NOTE that we dont' handle DMA boundary here + // because it shouldn't happen. -- the NT disk DD + // will take care of that. + if (BiosErrorCode & BIOS_TIME_OUT) { + SetLastError(ERROR_NO_MEDIA_IN_DRIVE); + break; + } + if (wRetry--) + goto BiosRetry; + SetLastError(BiosErrorToNTError(BiosErrorCode)); + break; + } + + } + setAX(AX); + setBX(BX); + setCX(CX); + setDX(DX); + setES(ES); + setCS(CS); + setIP(IP); + return SectorsRead; + +} + +DWORD BiosErrorToNTError(BYTE BiosErrorCode) +{ + DWORD NtErrorCode; + + switch (BiosErrorCode) { + case BIOS_INVALID_FUNCTION: + NtErrorCode = ERROR_BAD_COMMAND; + break; + case BIOS_BAD_ADDRESS_MARK: + NtErrorCode = ERROR_FLOPPY_ID_MARK_NOT_FOUND; + break; + case BIOS_WRITE_PROTECTED: + NtErrorCode = ERROR_WRITE_PROTECT; + break; + case BIOS_BAD_SECTOR: + case BIOS_CRC_ERROR: + NtErrorCode = ERROR_SECTOR_NOT_FOUND; + break; + case BIOS_DISK_CHANGED: + NtErrorCode = ERROR_DISK_CHANGE; + break; + case BIOS_NO_MEDIA: + NtErrorCode = ERROR_NO_MEDIA_IN_DRIVE; + break; + case BIOS_SEEK_ERROR: + NtErrorCode = ERROR_SEEK; + break; + default: + NtErrorCode = ERROR_FLOPPY_UNKNOWN_ERROR; + } + return NtErrorCode; + + +} + + +WORD demWinErrorToDosError(DWORD LastError) +{ + WORD DosError; + + switch(LastError) { + case ERROR_SEEK: + DosError = DOS_SEEK_ERROR; + break; + case ERROR_BAD_UNIT: + DosError = DOS_UNKNOWN_UNIT; + break; + case ERROR_NO_MEDIA_IN_DRIVE: + case ERROR_NOT_READY: + DosError = DOS_DRIVE_NOT_READY; + break; + case ERROR_NOT_DOS_DISK: + DosError = DOS_UNKNOWN_MEDIA; + break; + case ERROR_SECTOR_NOT_FOUND: + case ERROR_FLOPPY_WRONG_CYLINDER: + DosError = DOS_SECTOR_NOT_FOUND; + break; + case ERROR_READ_FAULT: + DosError = DOS_READ_FAULT; + break; + case ERROR_WRITE_FAULT: + DosError = DOS_WRITE_FAULT; + break; + case ERROR_WRONG_DISK: + case ERROR_DISK_CHANGE: + case ERROR_MEDIA_CHANGED: + DosError = DOS_INVALID_MEDIA_CHANGE; + break; + case ERROR_WRITE_PROTECT: + DosError = DOS_WRITE_PROTECTION; + break; + default: + DosError = DOS_GEN_FAILURE; + + } + return (DosError); +} + + +VOID demFdiskInit(VOID) +{ + PBDS pbds; + UCHAR Drive; + DISK_GEOMETRY DiskGeometry; + BPB bpb; + + Drive = 0; + do { + // first, the drive must be valid + // second, the drive must be a hard disk(fixed) + // third, the drive must be a FAT + if (demGetPhysicalDriveType(Drive) == DRIVE_FIXED && + nt_fdisk_init(Drive, &bpb, &DiskGeometry)) { + pbds = (PBDS) malloc(sizeof(BDS)); + if (pbds != NULL) { + pbds->bpb = bpb; + pbds->rbpb = bpb; + pbds->DrivePhys = NumberOfFdisk++; + pbds->DriveLog = Drive; + pbds->DriveType = DRIVETYPE_FDISK; + pbds->FormFactor = FF_FDISK; + pbds->TotalSectors = (bpb.Sectors) ? + bpb.Sectors : + bpb.BigSectors; + pbds->Cylinders = (WORD) DiskGeometry.Cylinders.LowPart; + pbds->Next = demBDS; + pbds->Flags = NON_REMOVABLE | PHYS_OWNER; + demBDS = pbds; + } + } + + } while (++Drive < 26); + +} + +VOID demFloppyInit(VOID) +{ + + WORD AX, BX, CX, DX, DI, ES; + BYTE i, NumberOfFloppy; + PBDS pbds; + BYTE DriveType; + + AX = getAX(); + BX = getBX(); + CX = getCX(); + DX = getDX(); + DI = getDI(); + ES = getES(); + + + // reset the floppy system + setDL(0); + setAH(DISKIO_RESET); + diskette_io(); + + setDL(0); + setAH(DISKIO_GETPARAMS); + diskette_io(); + if (getCF() == 0 && (NumberOfFloppy = getDL()) != 0) { + for(i = 0; i < NumberOfFloppy; i++) { + setDL(i); + setAH(DISKIO_GETPARAMS); + diskette_io(); + if (getCF() == 0) { + pbds = (PBDS) malloc(sizeof(BDS)); + if (pbds == NULL) { + OutputDebugStringOem("dem: not enough memory for BDS\n"); + break; + } + pbds->DrivePhys = pbds->DriveLog = i; + pbds->DriveType = DriveType = getBL() & 0x0F; + pbds->fd = NULL; + pbds->Cylinders = getCH() + 1; + pbds->Sectors = getCL(); + pbds->rbpb = StdBpb[DriveType - 1]; + pbds->TotalSectors = 0; + pbds->Next = demBDS; + pbds->FormFactor = FormFactorTable[DriveType - 1]; + demBDS = pbds; + pbds->Flags = UNFORMATTED_MEDIA | PHYS_OWNER; + setAH(DISKIO_DRIVETYPE); + setDL(i); + diskette_io(); + if (getAH() == 2 ) + pbds->Flags |= HAS_CHANGELINE; + } + } + } + setAX(AX); + setBX(BX); + setCX(CX); + setDX(DX); + setDI(DI); + setES(ES); +} diff --git a/private/mvdm/dos/dem/demdasd.h b/private/mvdm/dos/dem/demdasd.h new file mode 100644 index 000000000..9d41fe111 --- /dev/null +++ b/private/mvdm/dos/dem/demdasd.h @@ -0,0 +1,301 @@ + + +#pragma pack(1) + +#define MAX_FLOPPY_TYPE 5 +typedef struct A_DISKIO { + DWORD StartSector; + WORD Sectors; + WORD BufferOff; + WORD BufferSeg; +} DISKIO, * PDISKIO; + +// Bios Parameter Block (BPB) +typedef struct A_BPB { +WORD SectorSize; // sector size in bytes +BYTE ClusterSize; // cluster size in sectors +WORD ReservedSectors; // number of reserved sectors +BYTE FATs; // number of FATs +WORD RootDirs; // number of root directory entries +WORD Sectors; // number of sectors +BYTE MediaID; // media descriptor +WORD FATSize; // FAT size in sectors +WORD TrackSize; // track size in sectors; +WORD Heads; // number of heads +DWORD HiddenSectors; // number of hidden sectors +DWORD BigSectors; // number of sectors for big media +} BPB, *PBPB; + +typedef struct A_DPB { + +BYTE DriveNum; // driver numer, 0 - A, 1 -B and so on +BYTE Unit; // unit number of DPB in the driver +WORD SectorSize; // sector size in bytes +BYTE ClusterMask; // cluster mask +BYTE ClusterShift; // cluster shift count +WORD FATSector; // starting sector of FAT +BYTE FATs; // number of FAT +WORD RootDirs; // number of root directory entries +WORD FirstDataSector; // first sector for the first cluster +WORD MaxCluster; // number of cluster + 1 +WORD FATSize; // FAT size in sectors +WORD DirSector; // starting sector of directory +DWORD DriveAddr; // address of the corresponding driver +BYTE MediaID; // media ID +BYTE FirstAccess; // 0xFF if this DPB is first accessed +struct A_DPB * Next; // next DPB +WORD FreeCluster; // cluster # of the last allocated +WORD FreeClusters; // number of free clusters, 0xFFFF + // if unknown +} DPB, * PDPB; + + +typedef struct A_DEVICEPARAMETERS { +BYTE Functions; +BYTE DeviceType; +WORD DeviceAttrs; +WORD Cylinders; +BYTE MediaType; +BPB bpb; +} DEVICEPARAMETERS, *PDEVICE_PARAMETERS; + +#define LABEL_LENGTH 11 +#define FILESYSTYPE_LENGTH 8 + + +typedef struct _DISK_LABEL { +CHAR Name[LABEL_LENGTH]; +} DISK_LABEL, *PDISK_LABEL; + +typedef struct _FILESYSTYPE { +CHAR Name[FILESYSTYPE_LENGTH]; +} FILESYSTYPE, * PFILESYSTYPE; + +// Functions for Get Device Parameters +#define BUILD_DEVICE_BPB 0x01 + +// Functions for Set Device Parameters +#define INSTALL_FAKE_BPB 0x01 +#define ONLY_SET_TRACKLAYOUT 0x02 +#define TRACK_LAYOUT_IS_GOOD 0x04 +// Functions for Format Track +#define STATUS_FOR_FORMAT 0x01 +// error code from format status call +#define FORMAT_NO_ROM_SUPPORTED 0x01 +#define FORMAT_COMB_NOT_SUPPORTED 0x02 + + +// read and write block +typedef struct _RWBLOCK { +BYTE Functions; +WORD Head; +WORD Cylinder; +WORD StartSector; +WORD Sectors; +WORD BufferOff; +WORD BufferSeg; +} RW_BLOCK, *PRW_BLOCK; + +// format and verify track block +typedef struct _FMT_BLOCK{ +BYTE Functions; +WORD Head; +WORD Cylinder; +} FMT_BLOCK, *PFMT_BLOCK; + +// media id block +typedef struct _MID { +WORD InfoLevel; +DWORD SerialNum; +DISK_LABEL Label; +FILESYSTYPE FileSysType; +} MID, *PMID; + +// access flage +typedef struct _ACCESSCTRL { +BYTE Functions; +BYTE AccessFlag; +} ACCESSCTRL, * PACCESSCTRL; + +// bit definitions for flags + +// definitions for misc flags +#define NON_REMOVABLE 0x01 +#define HAS_CHANGELINE 0x02 +#define RETURN_FAKE_BPB 0x04 +#define GOOD_TRACKLAYOUT 0x08 +#define MULTI_OWNER 0x10 +#define PHYS_OWNER 0x20 +#define MEDIA_CHANGED 0x40 +#define CHANGED_BY_FORMAT 0x100 +#define UNFORMATTED_MEDIA 0x200 +#define FIRSTACCESS 0x8000 + +#define EXT_BOOTSECT_SIG 0x29 + +typedef struct _BOOTSECTOR { + BYTE Jump; + BYTE Target[2]; + BYTE OemName[8]; + BPB bpb; + BYTE DriveNum; + BYTE Reserved; + BYTE ExtBootSig; + DWORD SerialNum; + DISK_LABEL Label; + FILESYSTYPE FileSysType; +} BOOTSECTOR, * PBOOTSECTOR; + +// Bios Data Structure (BDS) +typedef struct A_BDS { +struct A_BDS *Next; //pointer to next bds +BYTE DrivePhys; //physical drive number, 0 based +BYTE DriveLog; //logical drive number, 0 based +BPB bpb; +BYTE FatSize; +WORD OpenCount; +BYTE MediaType; +WORD Flags; +WORD Cylinders; +BPB rbpb; +BYTE LastTrack; +DWORD Time; +DWORD SerialNum; +DISK_LABEL Label; +FILESYSTYPE FileSysType; +BYTE FormFactor; +// the fllowing fields are dedicated for the drive itself +WORD DriveType; +WORD Sectors; +HANDLE fd; +DWORD TotalSectors; +} BDS, *PBDS; + +#pragma pack() + +// drive type +#define DRIVETYPE_NULL 0 +#define DRIVETYPE_360 1 +#define DRIVETYPE_12M 2 +#define DRIVETYPE_720 3 +#define DRIVETYPE_144 4 +#define DRIVETYPE_288 5 +#define DRIVETYPE_FDISK 0xff +// FORM FACTOR + +#define FF_360 0 +#define FF_120 1 +#define FF_720 2 +#define FF_FDISK 5 +#define FF_144 7 +#define FF_288 9 +#define DOS_DIR_ENTRY_LENGTH 32 +#define DOS_DIR_ENTRY_LENGTH_SHIFT_COUNT 5 + +// bios diskette i/o functions +#define DISKIO_RESET 0 +#define DISKIO_GETSTATUS 1 +#define DISKIO_READ 2 +#define DISKIO_WRITE 3 +#define DISKIO_VERIFY 4 +#define DISKIO_FORMAT 5 +#define DISKIO_GETPARAMS 8 +#define DISKIO_DRIVETYPE 0x15 +#define DISKIO_DISKCHANGE 0x16 +#define DISKIO_SETTYPE 0x17 +#define DISKIO_SETMEDIA 0x18 +#define DISKIO_INVALID 0xff + +// Block device generic IOCTL(RAWIO) subfunction code + +#define IOCTL_SETDPM 0x40 +#define IOCTL_WRITETRACK 0x41 +#define IOCTL_FORMATTRACK 0x42 +#define IOCTL_SETMEDIA 0x46 +#define IOCTL_SETACCESS 0x47 +#define IOCTL_GETDPM 0x60 +#define IOCTL_READTRACK 0x61 +#define IOCTL_VERIFYTRACK 0x62 +#define IOCTL_GETMEDIA 0x66 +#define IOCTL_GETACCESS 0x67 +#define IOCTL_SENSEMEDIA 0x68 + +#define IOCTL_GENERIC_MIN IOCTL_SETDPM +#define IOCTL_GENERIC_MAX IOCTL_SENSEMEDIA + + +// dos error code + +#define DOS_WRITE_PROTECTION 0 +#define DOS_UNKNOWN_UNIT 1 +#define DOS_DRIVE_NOT_READY 2 +#define DOS_CRC_ERROR 4 +#define DOS_SEEK_ERROR 6 +#define DOS_UNKNOWN_MEDIA 7 +#define DOS_SECTOR_NOT_FOUND 8 +#define DOS_WRITE_FAULT 10 +#define DOS_READ_FAULT 11 +#define DOS_GEN_FAILURE 12 +#define DOS_INVALID_MEDIA_CHANGE 15 + +//BIOS disk io error code +#define BIOS_INVALID_FUNCTION 0x01 +#define BIOS_BAD_ADDRESS_MARK 0x02 +#define BIOS_WRITE_PROTECTED 0x03 +#define BIOS_BAD_SECTOR 0x04 +#define BIOS_DISK_CHANGED 0x05 +#define BIOS_DMA_OVERRUN 0x06 +#define BIOS_DMA_BOUNDARY 0x08 +#define BIOS_NO_MEDIA 0x0C +#define BIOS_CRC_ERROR 0x10 +#define BIOS_FDC_ERROR 0x20 +#define BIOS_SEEK_ERROR 0x40 +#define BIOS_TIME_OUT 0x80 + +// dos disk generic io control error code +#define DOS_INVALID_FUNCTION 1 +#define DOS_FILE_NOT_FOUND 2 +#define DOS_ACCESS_DENIED 5 + +#define BIOS_DISKCHANGED 6 + +#define BYTES_PER_SECTOR 512 + +VOID demDasdInit(VOID); +VOID demFloppyInit(VOID); +VOID demFdiskInit(VOID); +VOID demAbsReadWrite(BOOL IsWrite); +DWORD demDasdRead(PBDS pbds, DWORD StartSector, DWORD Sectors, + WORD BufferOff, WORD BufferSeg); +DWORD demDasdWrite(PBDS pbds, DWORD StartSector, DWORD Sectors, + WORD BufferOff, WORD BufferSeg); +BOOL demDasdFormat(PBDS pbds, DWORD Head, DWORD Cylinder, MEDIA_TYPE * Media); +BOOL demDasdVerify(PBDS pbds, DWORD Cylinder, DWORD Head); +PBDS demGetBDS(BYTE Drive); +BOOL demGetBPB(PBDS pbds); +WORD demWinErrorToDosError(DWORD LastError); +VOID diskette_io(VOID); + +DWORD BiosErrorToNTError(BYTE BiosError); +DWORD demBiosDiskIoRW(PBDS pbds, DWORD StartSector, DWORD Sectors, + WORD BufferOff, WORD BufferSeg, BOOL IsWrite); +VOID sas_loadw(DWORD, WORD *); + +// imported from host floppy support module +BOOL nt_floppy_close(BYTE drive); +ULONG nt_floppy_read(BYTE drive, ULONG offset, ULONG size, PBYTE buffer); +ULONG nt_floppy_write(BYTE drive, ULONG offset, ULONG size, PBYTE buffer); +ULONG nt_floppy_format(BYTE drive, WORD cylinder, WORD head, MEDIA_TYPE media); +BOOL nt_floppy_media_check(BYTE drive); +MEDIA_TYPE nt_floppy_get_media_type(BYTE Drive, WORD Cylinders, WORD Sectors, WORD Heads); +BOOL nt_floppy_verify(BYTE drive, DWORD offset, DWORD size); + +BOOL nt_fdisk_init(BYTE drive, PBPB bpb, PDISK_GEOMETRY disk_geometry); +ULONG nt_fdisk_read(BYTE drive, PLARGE_INTEGER offset, ULONG size, PBYTE buffer); +ULONG nt_fdisk_write(BYTE drive,PLARGE_INTEGER offset, ULONG size, PBYTE buffer); +BOOL nt_fdisk_verify(BYTE drive, PLARGE_INTEGER offset, ULONG size); +BOOL nt_fdisk_close(BYTE drive); +extern PBDS demBDS; +extern BYTE NumberOfFloppy, NumberOfFdisk; + +#define demIsDriveFloppy(DriveLog) (DriveLog < NumberOfFloppy) diff --git a/private/mvdm/dos/dem/demdata.c b/private/mvdm/dos/dem/demdata.c new file mode 100644 index 000000000..d784bcde1 --- /dev/null +++ b/private/mvdm/dos/dem/demdata.c @@ -0,0 +1,24 @@ +/* demdata.c - All the VDM instance Data. + * + * Sudeepb 06-Apr-1991 Created + */ + +#include "dem.h" + +/** VDM's DTA Address **/ +ULONG UNALIGNED *pulDTALocation; // Address in ntdos where DTA address is kept. + + +/** VDM's Current PDB **/ + +PUSHORT pusCurrentPDB; + +/** SFT Chain Head **/ + +PDOSSF pSFTHead = NULL; + +// +// address of extended error information in DOS data segment +// + +PDEMEXTERR pExtendedError; diff --git a/private/mvdm/dos/dem/demdir.c b/private/mvdm/dos/dem/demdir.c new file mode 100644 index 000000000..def89eb3d --- /dev/null +++ b/private/mvdm/dos/dem/demdir.c @@ -0,0 +1,182 @@ +/* demdir.c - SVC handlers for directory calls + * + * DemCreateDir + * DemDeleteDir + * DemQueryCurrentDir + * DemSetCurrentDir + * + * Modification History: + * + * Sudeepb 04-Apr-1991 Created + */ + +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> + +/* demCreateDir - Create a directory + * + * + * Entry - Client (DS:DX) directory name to create + * Client (BX:SI) EAs (NULL if no EAs) + * + * Exit + * SUCCESS + * Client (CY) = 0 + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = system status code + * + * + * Notes : Extended Attributes is not yet taken care of. + */ + +VOID demCreateDir (VOID) +{ +LPSTR lpDir; + + // EAs not yet implemented + if (getBX() || getSI()){ + demPrintMsg (MSG_EAS); + return; + } + + lpDir = (LPSTR) GetVDMAddr (getDS(),getDX()); + + + if(CreateDirectoryOem (lpDir,NULL) == FALSE){ + demClientError(INVALID_HANDLE_VALUE, *lpDir); + return; + } + + setCF(0); + return; +} + + +/* demDeleteDir - Create a directory + * + * + * Entry - Client (DS:DX) directory name to create + * + * Exit + * SUCCESS + * Client (CY) = 0 + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = system status code + * + */ + +VOID demDeleteDir (VOID) +{ +LPSTR lpDir; + + lpDir = (LPSTR) GetVDMAddr (getDS(),getDX()); + + if (RemoveDirectoryOem(lpDir) == FALSE){ + demClientError(INVALID_HANDLE_VALUE, *lpDir); + return; + } + + setCF(0); + return; +} + + + +/* demQueryCurrentDir - 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 + */ +VOID demQueryCurrentDir (VOID) +{ +PCDS pcds; +DWORD dw; +CHAR chDrive; +CHAR pPath[]="?:\\"; +CHAR EnvVar[] = "=?:"; + + pcds = (PCDS)GetVDMAddr(getDS(),getSI()); + + // validate media + chDrive = getAL() + 'A'; + pPath[0] = chDrive; + dw = GetFileAttributesOem(pPath); + if (dw == 0xFFFFFFFF || !(dw & FILE_ATTRIBUTE_DIRECTORY)) + { + demClientError(INVALID_HANDLE_VALUE, chDrive); + return; + } + + // 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); + } + + setCF(0); + return; +} + + + +/* demSetCurrentDir - Set the current directory + * + * + * Entry - Client (DS:DX) directory name + * + * Exit + * SUCCESS + * Client (CY) = 0 + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = system status code + * + */ + +VOID demSetCurrentDir (VOID) +{ +LPSTR lpBuf; +CHAR EnvVar[] = "=?:",ch; + + lpBuf = (LPSTR) GetVDMAddr (getDS(),getDX()); + ch = toupper(*(PCHAR)lpBuf); + if (ch < 'A' || ch > 'Z'){ + setCF(1); + return; + } + + if (SetCurrentDirectoryOem (lpBuf) == FALSE){ + demClientError(INVALID_HANDLE_VALUE, *lpBuf); + return; + } + + EnvVar[1] = *(PCHAR)lpBuf; + if(SetEnvironmentVariableOem ((LPSTR)EnvVar,lpBuf) == FALSE) + setCF(1); + else + setCF(0); + return; +} diff --git a/private/mvdm/dos/dem/demdisp.c b/private/mvdm/dos/dem/demdisp.c new file mode 100644 index 000000000..c498e4b5b --- /dev/null +++ b/private/mvdm/dos/dem/demdisp.c @@ -0,0 +1,245 @@ +/* + * demdisp.c - SVC dispatch module + * + * Modification History: + * + * Sudeepb 31-Mar-1991 Created + */ + +#include "dem.h" +#include <stdio.h> +#include <softpc.h> + + +#if DBG + +PCHAR aSVCNames[] = { + "demChgFilePtr", + "demChMod", + "demClose", + "demCreate", + "demCreateDir", + "demDelete", + "demDeleteDir", + "demDeleteFCB", + "demFileTimes", + "demFindFirst", + "demFindFirstFCB", + "demFindNext", + "demFindNextFCB", + "demGetBootDrive", + "demGetDriveFreeSpace", + "demGetDrives", + "demGSetMediaID", + "demLoadDos", + "demOpen", + "demQueryCurrentDir", + "demQueryDate", + "demQueryTime", + "demRead", + "demRename", + "demSetCurrentDir", + "demSetDate", + "demSetDefaultDrive", + "demSetDTALocation", + "demSetTime", + "demSetV86KernelAddr", + "demWrite", + "demGetDriveInfo", + "demRenameFCB", + "demIOCTL", + "demCreateNew", + "DemDiskReset", + "DemSetDPB", + "DemGetDPB", + "DemSleazeFunc", + "demCommit", + "DemExtHandle", + "DemAbsDRD", + "DemAbsDWRT", + "DemGsetCDPG", + "DemCreateFCB", + "DemOpenFCB", + "DemCloseFCB", + "DemFCBIO", + "DemDate16", + "DemGetFileInfo", + "DemSetHardErrorInfo", + "DemRetry", + "DemLoadDosAppSym", + "DemFreeDosAppSym", + "DemEntryDosApp", + "DemDOSDispCall", + "DemDOSDispRet", + "DemOutputString", + "DemInputString", + "DemIsDebug", + "DemTerminatePDB", + "DemExitVDM", + "DemWOWFiles", + "DemLockOper", + "demNotYetImplemented", + "DemGetComputerName", + "DemFastRead", + "DemFastWrite", + "DemCheckPath", + "DemSystemSymbolOp", + "DemGetDpbList", + "DemPipeFileDataEOF", + "DemPipeFileEOF" +}; + +#endif // DBG + +DWORD fShowSVCMsg = 0; +ULONG CurrentISVC; + + +PFNSVC apfnSVC [] = { + demChgFilePtr, //SVC_DEMCHGFILEPTR + demChMod, //SVC_DEMCHMOD + demClose, //SVC_DEMCLOSE + demCreate, //SVC_DEMCREATE + demCreateDir, //SVC_DEMCREATEDIR + demDelete, //SVC_DEMDELETE + demDeleteDir, //SVC_DEMDELETEDIR + demDeleteFCB, //SVC_DEMDELETEFCB + demFileTimes, //SVC_DEMFILETIMES + demFindFirst, //SVC_DEMFINDFIRST + demFindFirstFCB, //SVC_DEMFINDFIRSTFCB + demFindNext, //SVC_DEMFINDNEXT + demFindNextFCB, //SVC_DEMFINDNEXTFCB + demGetBootDrive, //SVC_DEMGETBOOTDRIVE + demGetDriveFreeSpace, //SVC_DEMGETDRIVEFREESPACE + demGetDrives, //SVC_DEMGETDRIVES + demGSetMediaID, //SVC_DEMGSETMEDIAID + demLoadDos, //SVC_DEMLOADDOS + demOpen, //SVC_DEMOPEN + demQueryCurrentDir, //SVC_DEMQUERYCURRENTDIR + demQueryDate, //SVC_DEMQUERYDATE + demQueryTime, //SVC_DEMQUERYTIME + demRead, //SVC_DEMREAD + demRename, //SVC_DEMRENAME + demSetCurrentDir, //SVC_DEMSETCURRENTDIR + demSetDate, //SVC_DEMSETDATE + demSetDefaultDrive, //SVC_DEMSETDEFAULTDRIVE + demSetDTALocation, //SVC_DEMSETDTALOCATION + demSetTime, //SVC_DEMSETTIME + demSetV86KernelAddr, //SVC_DEMSETV86KERNELADDR + demWrite, //SVC_DEMWRITE + demNotYetImplemented, //SVC_GETDRIVEINFO + demRenameFCB, //SVC_DEMRENAMEFCB + demIOCTL, //SVC_DEMIOCTL + demCreateNew, //SVC_DEMCREATENEW + demDiskReset, //SVC_DEMDISKRESET + demNotYetImplemented, //SVC_DEMSETDPB + demGetDPB, //SVC_DEMGETDPB + demNotYetImplemented, //SVC_DEMSLEAZEFUNC + demCommit, //SVC_DEMCOMMIT + demNotYetImplemented, //SVC_DEMEXTHANDLE + demAbsRead, //SVC_DEMABSDRD + demAbsWrite, //SVC_DEMABSDWRT + demNotYetImplemented, //SVC_DEMGSETCDPG + demCreateFCB, //SVC_DEMCREATEFCB + demOpenFCB, //SVC_DEMOPENFCB + demCloseFCB, //SVC_DEMCLOSEFCB + demFCBIO, //SVC_FCBIO + demDate16, //SVC_DEMDATE16 + demGetFileInfo, //SVC_DEMGETFILEINFO + demSetHardErrorInfo, //SVC_DEMSETHARDERRORINFO + demRetry, //SVC_DEMRETRY + demLoadDosAppSym, //SVC_DEMLOADDOSAPPSYM + demFreeDosAppSym, //SVC_DEMFREEDOSAPPSYM + demEntryDosApp, //SVC_DEMENTRYDOSAPP + demDOSDispCall, //SVC_DEMDOSDISPCALL + demDOSDispRet, //SVC_DEMDOSDISPRET + demOutputString, //SVC_OUTPUT_STRING + demInputString, //SVC_INPUT_STRING + demIsDebug, //SVC_ISDEBUG + demTerminatePDB, //SVC_PDBTERMINATE + demExitVDM, //SVC_DEMEXITVDM + demWOWFiles, //SVC_DEMWOWFILES + demLockOper, //SVC_DEMLOCKOPER + demNotYetImplemented, //SVC_DEMNOTYETIMPLEMENTED + demGetComputerName, //SVC_DEMGETCOMPUTERNAME + demNotYetImplemented, //SVC_DEMFASTREAD + demNotYetImplemented, //SVC_DEMFASTWRITE + demCheckPath, //SVC_DEMCHECKPATH + demSystemSymbolOp, //SVC_DEMSYSTEMSYMBOLOP + demGetDPBList, //SVC_DEMBUILDDPBLIST + demPipeFileDataEOF, //SVC_DEMPIPEFILEDATAEOF + demPipeFileEOF //SVC_DEMPIPEFILEEOF +}; + + +/* DemDispatch - Dispatch SVC call to right handler. + * + * Entry - iSvc (SVC byte following SVCop) + * + * Exit - None + * + * Note - Some mechanism has to be worked out to let the emulator know + * about DOSKRNL code segment and size. Using these it will figure + * out whether SVCop (hlt for the moment) has to be passed to + * DEM or to be handled as normal invalid opcode. + */ + +BOOL DemDispatch (ULONG iSvc) +{ +#if DBG + if(iSvc < SVC_DEMLASTSVC && (fShowSVCMsg & DEMSVCTRACE) && + apfnSVC[iSvc] != demNotYetImplemented){ + sprintf(demDebugBuffer,"DemDispatch: Entering %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); + } +#endif + + if (iSvc >= SVC_DEMLASTSVC){ +#if DBG + sprintf(demDebugBuffer,"Unimplemented SVC index %x\n",iSvc); + OutputDebugStringOem(demDebugBuffer); +#endif + setCF(1); + return FALSE; + } + + if (pHardErrPacket) { + pHardErrPacket->vhe_fbInt24 = 0; + } + CurrentISVC = iSvc; + (apfnSVC [iSvc])(); + + +#if DBG + if((fShowSVCMsg & DEMSVCTRACE)){ + sprintf(demDebugBuffer,"DemDispatch:On Leaving %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 TRUE; +} + +VOID demNotYetImplemented (VOID) +{ + if (fShowSVCMsg) { + sprintf(demDebugBuffer,"Unimplemented SVC %d\n",CurrentISVC); + OutputDebugStringOem(demDebugBuffer); + } + + setCF(0); + return; +} + +VOID demSetV86KernelAddr (VOID) +{ + // Here debugger callout has to be made for DOSKRNL symbols + return; +} diff --git a/private/mvdm/dos/dem/demerror.c b/private/mvdm/dos/dem/demerror.c new file mode 100644 index 000000000..2775ddc23 --- /dev/null +++ b/private/mvdm/dos/dem/demerror.c @@ -0,0 +1,388 @@ +/* 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 + * + */ + +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; + + if ((ulErrCode < ERROR_WRITE_PROTECT || ulErrCode > ERROR_GEN_FAILURE) + && ulErrCode != ERROR_WRONG_DISK ) + { +#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); + + 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; +} diff --git a/private/mvdm/dos/dem/demfcb.c b/private/mvdm/dos/dem/demfcb.c new file mode 100644 index 000000000..275595d1a --- /dev/null +++ b/private/mvdm/dos/dem/demfcb.c @@ -0,0 +1,768 @@ +/* demfcb.c - SVC handlers for misc. FCB operations + * + * demCloseFCB + * demCreateFCB + * demDate16 + * demDeleteFCB + * demFCBIO + * demGetFileInfo + * demOpenFCB + * demRenameFCB + * + * Modification History: + * + * Sudeepb 09-Apr-1991 Created + * Sudeepb 21-Nov-1991 Added FCB based IO functions + * Jonle 30-Jun-1994 add wild card support for fcb rename + */ + +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> +#include <winbase.h> +#include <mvdm.h> + +#define DOT '.' +#define QMARK '?' + + +/* demDeleteFCB - FCB based File Delete + * + * + * Entry - Client (ES:DI) - Full File Path + * Client (AL) - 0 if not extended FCB + * Client (DL) - File Attr. to be deleted (valid only if Al !=0 ) + * + * Exit + * SUCCESS + * Client (CF) = 0 + * + * FAILURE + * Client (CF) = 1 + * Client (AX) = system status code + * HARD ERROR + * Client (CF) = 1 + * Client (AX) = 0ffffh + * + * Notes: Following are the rules for FCB based delete: + * 1. If normal FCB than dont allow delete on hidden,system files + * 2. if extended FCB than search attributes should include hidden, + * system or read-only if that kind of file is to be deleted. + */ + +VOID demDeleteFCB (VOID) +{ +HANDLE hFind; +LPSTR lpFileName; +BYTE bClientAttr=0; +BOOL fExtendedFCB=FALSE; +WIN32_FIND_DATA wfBuffer; +BOOL fSuccess = FALSE; +DWORD dwAttr; +USHORT uErr; + +CHAR szPath_buffer[_MAX_PATH]; +CHAR szDrive[_MAX_DRIVE]; +CHAR szDir[_MAX_DIR]; +CHAR szFname[_MAX_FNAME]; +CHAR szExt[_MAX_EXT]; + +DWORD dwErrCode = 0, dwErrCodeKeep = 0; + + // Get the file name + lpFileName = (LPSTR) GetVDMAddr (getES(),getDI()); + + _splitpath( lpFileName, szDrive, szDir, szFname, szExt ); + + // Check if handling extended FCB + if(getAL() != 0){ + bClientAttr = getDL(); + + /* Special case for delete volume label (INT 21 Func 13H, Attr = 8H */ + + if((bClientAttr == ATTR_VOLUME_ID)) { + if((uErr = demDeleteLabel(lpFileName[DRIVEBYTE]))) { + setCF(1); + setAX(uErr); + return; + } + setAX(0); + setCF(0); + return; + } + + + bClientAttr &= (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM); + fExtendedFCB = TRUE; + } + + // Find the first instance of file + if((hFind = FindFirstFileOem (lpFileName,&wfBuffer)) == (HANDLE)-1){ + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + + // loop for all files which match the name and attributes + do { + // Check if read_only,hidden or system file + if((dwAttr= wfBuffer.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | + FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))){ + + // if so, try next file if normal FCB case. If extended fcb case + // then check if right attributes are given by client. + if(fExtendedFCB && ((dwAttr & (DWORD)bClientAttr) == dwAttr)){ + + // Yes, right attributes are given. So if the file is read + // only then change the modes to normal. Note NT will + // delete hidden and system files anyway. + if (dwAttr & FILE_ATTRIBUTE_READONLY){ + strcpy( szPath_buffer, szDrive); + strcat( szPath_buffer, szDir); + strcat( szPath_buffer, wfBuffer.cFileName); + + // if set attributes fail try next file + if(SetFileAttributesOem (szPath_buffer, + FILE_ATTRIBUTE_NORMAL) == -1) + continue; + } + } + else { + dwErrCodeKeep = ERROR_ACCESS_DENIED; + continue; + } + } + + strcpy( szPath_buffer, szDrive); + strcat( szPath_buffer, szDir); + strcat( szPath_buffer, wfBuffer.cFileName); + + if(DeleteFileOem(szPath_buffer) == FALSE) { + dwErrCode = GetLastError(); + + SetLastError(dwErrCode); + + if (((dwErrCode >= ERROR_WRITE_PROTECT) && + (dwErrCode <= ERROR_GEN_FAILURE)) || + dwErrCode == ERROR_WRONG_DISK ) { + demClientError(INVALID_HANDLE_VALUE, szPath_buffer[0]); + return; + } + continue; + } + + // We have deleted at least one file, so report success + fSuccess = TRUE; + + } while (FindNextFileOem(hFind,&wfBuffer) == TRUE); + + if(FindClose(hFind) == FALSE) + demPrintMsg (MSG_INVALID_HFIND); + + if (fSuccess == TRUE){ + setCF(0); + return; + } + + setCF(1); + + if(dwErrCodeKeep) + setAX((SHORT) dwErrCodeKeep); + else + setAX(ERROR_FILE_NOT_FOUND); + return; +} + + +/* demRenameFCB - FCB based Rename file + * + * Entry - Client (DS:SI) Sources file to be renamed + * Client (ES:DI) Destination file to be renamed to + * + * Exit - SUCCESS + * Client (CF) = 0 + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ + +VOID demRenameFCB (VOID) +{ + LPSTR lpSrc,lpDst; + DWORD dw; + HANDLE hFind; + PCHAR pNewDstFilePart; + PCHAR pDstFilePart; + PCHAR pCurrSrcFilePart; + WIN32_FIND_DATA W32FindData; + CHAR NewDst[MAX_PATH]; + CHAR CurrSrc[MAX_PATH]; + + lpSrc = (LPSTR) GetVDMAddr (getDS(),getSI()); + lpDst = (LPSTR) GetVDMAddr (getES(),getDI()); + + // Find the first instance of the source file + hFind = FindFirstFileOem (lpSrc,&W32FindData); + if (hFind == INVALID_HANDLE_VALUE) { + dw = GetLastError(); + if (dw == ERROR_BAD_PATHNAME || dw == ERROR_DIRECTORY ) { + SetLastError(ERROR_PATH_NOT_FOUND); + } + demClientError(INVALID_HANDLE_VALUE, *lpSrc); + return; + } + + // + // Source string consists of the path taken from the original + // source specified plus the filename part retrieved from the + // FindFile call + // + strcpy(CurrSrc, lpSrc); + pCurrSrcFilePart = strrchr(CurrSrc, '\\'); + pCurrSrcFilePart++; + + // + // Destination string is template for meta character substitution + // + pDstFilePart = strrchr(lpDst, '\\'); + pDstFilePart++; + + // + // NewDst string is constructed from template and the source string + // when doing meta file character substitution. + // + strcpy(NewDst, lpDst); + pNewDstFilePart = strrchr(NewDst, '\\'); + pNewDstFilePart++; + + + do { + PCHAR pNew; + PCHAR pSrc; + PCHAR pDst; + + strcpy(pCurrSrcFilePart, + W32FindData.cAlternateFileName[0] + ? W32FindData.cAlternateFileName + : W32FindData.cFileName //// ??? hpfs lfns ???? + ); + + pSrc = pCurrSrcFilePart; // source fname + pNew = pNewDstFilePart; // dest fname to be constructed + pDst = pDstFilePart; // raw dest fname template (with metas) + + while (*pDst) { + + // + // If Found a '?' in Dest template, use character from src + // + if (*pDst == QMARK) { + if (*pSrc != DOT && *pSrc) + *pNew++ = *pSrc++; + } + + // + // if Found a DOT in Dest template, Align DOTS between Src\Dst + // + else if (*pDst == DOT) { + while (*pSrc != DOT && *pSrc) { // mov src to one past DOT + pSrc++; + } + if (*pSrc) + pSrc++; + + *pNew++ = DOT; + } + + // + // Nothing special found, use character from Dest template + // + else { + if (*pSrc != DOT && *pSrc) + pSrc++; + *pNew++ = *pDst; + } + + pDst++; + } + + *pNew = '\0'; + + // + // MoveFile does not return error if dst and src are the same, + // but DOS does, so check first.. + // + if (!_stricmp (CurrSrc, NewDst)) { + setCF(1); + setAX(0x5); + FindClose(hFind); + return; + } + + if (!MoveFileOem(CurrSrc, NewDst)){ + demClientError(INVALID_HANDLE_VALUE, *lpSrc); + FindClose(hFind); + return; + } + + } while (FindNextFileOem(hFind,&W32FindData)); + + + + // + // If the search on the source string for any reason besides + // no more files, then its a genuine error. + // + dw = GetLastError(); + if (dw != ERROR_NO_MORE_FILES) { + if (dw == ERROR_BAD_PATHNAME || dw == ERROR_DIRECTORY ) { + SetLastError(ERROR_PATH_NOT_FOUND); + } + demClientError(INVALID_HANDLE_VALUE, *lpSrc); + } + else { + setCF(0); + } + + FindClose(hFind); + return; +} + + + +/* demCloseFCB - Close the NT handle associated with the FCB being closed. + * + * Entry - Client (AX:SI) DWORD NT handle + * + * Exit - SUCCESS + * Client (CF) = 0 + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ + +VOID demCloseFCB (VOID) +{ +HANDLE hFile; + + hFile = GETHANDLE (getAX(),getSI()); + + if(hFile == 0) { + + setCF(0); + return; + } + + if (CloseHandle (hFile) == FALSE){ + + demClientError(hFile, (CHAR)-1); + return; + + } + setCF(0); + return; +} + +/* demCreateFCB - An FCB is being created get the NT handle. + * + * Entry - Client (AL) Creation Mode + * 00 - Normal File + * 01 - Read-only file + * 02 - Hidden File + * 04 - System file + * Client (DS:SI) Full path filename + * Client (ES:DI) SFT address + * + * Exit - SUCCESS + * Client (CF) = 0 + * Client (AX:BP) = NT Handle + * Client (BX) = Time + * Client (CX) = Date + * Client (DX:SI) = Size + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ + +VOID demCreateFCB (VOID) +{ + demFCBCommon (CREATE_ALWAYS); + return; +} + +/* demDate16 - Get the current date/time in DOS FCB format. + * + * Entry - None + * + * Exit - Always Success + * Client (AX) has date + * Client (DX) has time + * NOTES: + * + * DemDate16 returns the current date in AX, current time in DX in this format + * AX - YYYYYYYMMMMDDDDD years months days + * DX - HHHHHMMMMMMSSSSS hours minutes seconds/2 + */ + +VOID demDate16 (VOID) +{ +SYSTEMTIME TimeDate; + + GetLocalTime(&TimeDate); + setAX ( (USHORT) ((TimeDate.wYear << 9 ) | + ((TimeDate.wMonth & 0xf) << 5 ) | + (TimeDate.wDay & 0x1f)) + ); + setDX ( (USHORT) ((TimeDate.wHour << 11) | + ((TimeDate.wMinute & 0x3f) << 5) | + ((TimeDate.wSecond / 2) & 0x1f)) + ); + return; +} + +/* demFCBIO - Carry out the FCB based IO operation. + * + * Entry - Client (BX) = 1 if read operation, 0 if write + * Client (AX:BP) NT Handle + * Client (DI:DX) offset to start the operation with + * Client (CX) Count of bytes + * + * Exit - SUCCESS + * Client (CF) = 0 + * Client (CX) = counts of bytes read/written + * Client (AX:BX) = size + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ + +VOID demFCBIO (VOID) +{ +HANDLE hFile; +ULONG CurOffset; +PVOID pBuf; +DWORD dwBytesIO; +DWORD dwSize,dwSizeHigh; +DWORD dwErrCode; + + hFile = GETHANDLE (getAX(),getBP()); + CurOffset = (((ULONG)getDI()) << 16) + (ULONG)getDX(); + + if (SetFilePointer (hFile, + (LONG)CurOffset, + NULL, + (DWORD)FILE_BEGIN) == -1L){ + demClientError(hFile, (CHAR)-1); + return ; + } + + pBuf = (PVOID)GetVDMAddr(*((PUSHORT)pulDTALocation + 1), + *((PUSHORT)pulDTALocation)); + + if(getBX()) { // Read Operation + if (ReadFile (hFile, + pBuf, + (DWORD)getCX(), + &dwBytesIO, + NULL) == FALSE){ + + Sim32FlushVDMPointer(*pulDTALocation, getCX(), pBuf, FALSE); + Sim32FreeVDMPointer(*pulDTALocation, getCX(), pBuf, FALSE); + demClientError(hFile, (CHAR)-1); + return ; + } + Sim32FlushVDMPointer (*pulDTALocation, getCX(),pBuf, FALSE); + Sim32FreeVDMPointer (*pulDTALocation, getCX(), pBuf, FALSE); + } + else { + if (WriteFile (hFile, + pBuf, + (DWORD)getCX(), + &dwBytesIO, + NULL) == FALSE) { + + // If disk is full then we should return number of bytes written + // AX = 1 and CF = 1 + + dwErrCode = GetLastError(); + if(dwErrCode == ERROR_DISK_FULL) { + + setCX( (USHORT) dwBytesIO); + setAX(1); + setCF(1); + return; + } + + SetLastError(dwErrCode); + + demClientError(hFile, (CHAR)-1); + return ; + + } + } + + // Get File Size + if((dwSize = GetFileSize(hFile,&dwSizeHigh)) == -1){ + + demPrintMsg(MSG_FILEINFO); + ASSERT(FALSE); + demClientError(hFile, (CHAR)-1); + return; + } + + if(dwSizeHigh) { + demPrintMsg(MSG_FILESIZE_TOOBIG); + ASSERT(FALSE); + demClientError(hFile, (CHAR)-1); + return; + } + + // Setup the exit registers + setCX((USHORT)dwBytesIO); + setBX((USHORT)dwSize); + setAX((USHORT)(dwSize >> 16 )); + setCF(0); + return; +} + +/* demGetFileInfo - Get Misc. file info in FCB format. + * + * Entry - Client (DS:SI) full path file name + * + * Exit - SUCCESS + * Client (CF) = 0 + * Client (AX) = Attribute of file + * Client (CX) = Time stamp of file + * Client (DX = Date stamp of file + * Client (BX:DI)= Size of file (32 bit) + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ + +VOID demGetFileInfo (VOID) +{ +HANDLE hFile; +LPSTR lpFileName; +WORD wDate,wTime; +DWORD dwSize,dwAttr; + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI()); + + if ((hFile = CreateFileOem(lpFileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL)) == (HANDLE)-1){ + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + + // Get Misc. INfo + if (demGetMiscInfo (hFile,&wTime, &wDate, &dwSize) == FALSE) { + CloseHandle (hFile); + return; + } + + CloseHandle (hFile); + + if ((dwAttr = GetFileAttributesOem (lpFileName)) == -1) { + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + + if (dwAttr == FILE_ATTRIBUTE_NORMAL) + dwAttr = 0; + + setAX((USHORT)dwAttr); + setCX(wTime); + setDX(wDate); + setDI((USHORT)dwSize); + setBX((USHORT)(dwSize >> 16)); + return; +} + + +/* demOpenFCB - An FCB is being opened get the NT handle. + * + * Entry - Client (AL) Open Mode + * Client (DS:SI) Full path filename + * + * Exit - SUCCESS + * Client (CF) = 0 + * Client (AX:BP) = NT Handle + * Client (BX) = Time + * Client (CX) = Date + * Client (DX:SI) = Size + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ + +VOID demOpenFCB (VOID) +{ + demFCBCommon (OPEN_EXISTING); + return; +} + +/* demFCBCommon - FCB Open/Create. + * + * Entry - CreateDirective - Open/Create + * Client (AL) Open Mode + * Client (DS:SI) Full path filename + * + * Exit - SUCCESS + * Client (CF) = 0 + * Client (AX:BP) = NT Handle + * Client (BX) = Time + * Client (CX) = Date + * Client (DX:SI) = Size + * + * FAILURE + * Client(CF) = 1 + * Client(AX) = error code + */ +VOID demFCBCommon (ULONG CreateDirective) +{ +HANDLE hFile; +LPSTR lpFileName; +UCHAR uchMode,uchAccess; +DWORD dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; +DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; +WORD wDate,wTime; +DWORD dwSize,dwAttr=0; +USHORT uErr; +SECURITY_ATTRIBUTES sa; + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI()); + uchMode = getAL(); + + /* Special case for delete volume label (INT 21 Func 13H, Attr = 8H */ + + if((uchMode == ATTR_VOLUME_ID) && (CreateDirective == CREATE_ALWAYS)) { + if((uErr = demCreateLabel(lpFileName[DRIVEBYTE], + lpFileName+LABELOFF))) { + setCF(1); + setAX(uErr); + return; + } + setAX(0); + setBP(0); + setCF(0); + return; + } + + + // In create case AL has creation attributes. By default + // Access is for read/write and sharing for both. In open + // case AL has appropriate access and sharing information. + if((CreateDirective == CREATE_ALWAYS) && ((uchMode &0xff) == 0)) { + + dwAttr = FILE_ATTRIBUTE_NORMAL; + dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ; + } + else { + uchAccess = uchMode & (UCHAR)ACCESS_MASK; + + if (uchAccess == OPEN_FOR_READ) + dwDesiredAccess = GENERIC_READ; + + else if (uchAccess == OPEN_FOR_WRITE) + dwDesiredAccess = GENERIC_WRITE; + + uchMode = uchMode & (UCHAR)SHARING_MASK; + + switch (uchMode) { + case SHARING_DENY_BOTH: + dwShareMode = 0; + break; + case SHARING_DENY_WRITE: + dwShareMode = FILE_SHARE_READ; + break; + case SHARING_DENY_READ: + dwShareMode = FILE_SHARE_WRITE; + break; + } + } + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + if ((hFile = CreateFileOem(lpFileName, + dwDesiredAccess, + dwShareMode | FILE_SHARE_DELETE, + &sa, + CreateDirective, + dwAttr, + NULL)) == (HANDLE)-1){ + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + + // Get Misc. INfo + if (demGetMiscInfo (hFile,&wTime, &wDate, &dwSize) == FALSE) + return; + + // Setup the exit registers + setBX(wTime); + setCX(wDate); + setBP((USHORT)hFile); + setAX((USHORT)((ULONG)hFile >> 16)); + setSI((USHORT)dwSize); + setDX((USHORT)(dwSize >> 16)); + setCF(0); + return; +} + + +BOOL demGetMiscInfo (hFile, lpTime, lpDate, lpSize) +HANDLE hFile; +LPWORD lpTime; +LPWORD lpDate; +LPDWORD lpSize; +{ +FILETIME LastWriteTime,ftLocal; +DWORD dwSizeHigh=0; + + if(GetFileTime (hFile,NULL,NULL,&LastWriteTime) == -1){ + demPrintMsg(MSG_FILEINFO); + ASSERT(FALSE); + demClientError(hFile, (CHAR)-1); + CloseHandle (hFile); + return FALSE; + } + + FileTimeToLocalFileTime (&LastWriteTime,&ftLocal); + + if(FileTimeToDosDateTime(&ftLocal, + lpDate, + lpTime) == FALSE){ + demPrintMsg(MSG_FILEINFO); + ASSERT(FALSE); + demClientError(hFile, (CHAR)-1); + return FALSE; + } + + if((*lpSize = GetFileSize(hFile,&dwSizeHigh)) == -1){ + demPrintMsg(MSG_FILEINFO); + ASSERT(FALSE); + demClientError(hFile, (CHAR)-1); + return FALSE; + } + + if(dwSizeHigh) { + demPrintMsg(MSG_FILESIZE_TOOBIG); + ASSERT(FALSE); + demClientError(hFile, (CHAR)-1); + return FALSE; + } + return TRUE; +} diff --git a/private/mvdm/dos/dem/demfile.c b/private/mvdm/dos/dem/demfile.c new file mode 100644 index 000000000..b2dc18357 --- /dev/null +++ b/private/mvdm/dos/dem/demfile.c @@ -0,0 +1,1160 @@ +/* demfile.c - SVC handlers for calls where file name is specified. + * + * demOpen + * demCreate + * demUnlink + * demChMod + * demRename + * + * Modification History: + * + * Sudeepb 02-Apr-1991 Created + * + */ + +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> +#include <winbase.h> +#include <vrnmpipe.h> +#include <nt_vdd.h> + +extern PDOSSF pSFTHead; + +BOOL (*VrInitialized)(VOID); // POINTER TO FUNCTION +extern BOOL LoadVdmRedir(VOID); +extern BOOL IsVdmRedirLoaded(VOID); + +BOOL +IsNamedPipeName( + IN LPSTR Name + ); + +BOOL +IsNamedPipeName( + IN LPSTR Name + ) + +/*++ + +Routine Description: + + Lifted from VDMREDIR.DLL - we don't want to load the entire DLL if we + need to check for a named pipe + + Checks if a string designates a named pipe. As criteria for the decision + we use: + + \\computername\PIPE\... + + DOS (client-side) can only open a named pipe which is created at a server + and must therefore be prefixed by a computername + +Arguments: + + Name - to check for (Dos) named pipe syntax + +Return Value: + + BOOL + TRUE - Name refers to (local or remote) named pipe + FALSE - Name doesn't look like name of pipe + +--*/ + +{ + int CharCount; + + + if (IS_ASCII_PATH_SEPARATOR(*Name)) { + ++Name; + if (IS_ASCII_PATH_SEPARATOR(*Name)) { + ++Name; + CharCount = 0; + while (*Name && !IS_ASCII_PATH_SEPARATOR(*Name)) { + ++Name; + ++CharCount; + } + if (!CharCount || !*Name) { + + // + // Name is \\ or \\\ or just \\name which I don't understand, + // so its not a named pipe - fail it + // + + return FALSE; + } + + // + // bump name past next path separator. Note that we don't have to + // check CharCount for max. length of a computername, because this + // function is called only after the (presumed) named pipe has been + // successfully opened, therefore we know that the name has been + // validated + // + + ++Name; + } else { + return FALSE; + } + + // + // We are at <something> (after \ or \\<name>\). Check if <something> + // is [Pp][Ii][Pp][Ee][\\/] + // + + if (!_strnicmp(Name, "PIPE", 4)) { + Name += 4; + if (IS_ASCII_PATH_SEPARATOR(*Name)) { + return TRUE; + } + } + } + return FALSE; +} + +/* demOpen - Open a file + * + * + * Entry - Client (DS:SI) Full path of File + * Client (BL) Open Mode + * Client (ES:DI) Address of extended attributes buffer + * Client (AL) 0 - No EA's ; 1 - EA's specified + * + * Exit + * SUCCESS + * Client (CY) = 0 + * Client (AX) = Assigned Open Handle (high word) + * Client (BP) = Assigned Open Handle (low word) + * Client (DX) = 1 if pipe was opened + * Client (BX) = High word of the file size + * Client (CX) = low word of the file size + * + * + * FAILURE + * CY = 1 + * AX = system status code + * HARD ERROR + * CY = 1 + * AX = 0FFFFh + * + * + * Notes : Extended Attributes is not yet taken care of. + */ + +VOID demOpen (VOID) +{ +HANDLE hFile; +LPSTR lpFileName; +UCHAR uchMode,uchAccess; +DWORD dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; +DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; +BOOL ItsANamedPipe = FALSE; +BOOL IsFirst; +LPSTR dupFileName; +DWORD dwFileSize,dwSizeHigh; +SECURITY_ATTRIBUTES sa; + + if (getAL()){ + demPrintMsg (MSG_EAS); + return; + } + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI()); + +#if DBG + if(fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demfile: Opening File <%s>\n",lpFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + // + // the DOS filename must be 'canonicalized': forward slashes (/) must be + // converted to back slashes (\) and the filename should be upper-cased + // using the current code page info + // + + // + // BUBUG: Kanji? (/other DBCS) + // + + if (strchr(lpFileName, '/')) { + lpFileName = _strdup(lpFileName); + if (lpFileName == NULL) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + for (dupFileName = lpFileName; *dupFileName; ++dupFileName) { + if (*dupFileName == '/') { + *dupFileName = '\\'; + } + } + dupFileName = lpFileName; + } else { + dupFileName = NULL; + } + + uchMode = getBL(); + uchAccess = uchMode & (UCHAR)ACCESS_MASK; + + if (uchAccess == OPEN_FOR_READ) + dwDesiredAccess = GENERIC_READ; + else if (uchAccess == OPEN_FOR_WRITE) + dwDesiredAccess = GENERIC_WRITE; + + uchMode = uchMode & (UCHAR)SHARING_MASK; + + switch (uchMode) { + case SHARING_DENY_BOTH: + dwShareMode = 0; + break; + case SHARING_DENY_WRITE: + dwShareMode = FILE_SHARE_READ; + break; + case SHARING_DENY_READ: + dwShareMode = FILE_SHARE_WRITE; + break; + // compatible mode is a special case + case SHARING_COMPAT: + dwShareMode |= FILE_SHARE_DELETE; + //dwDesiredAccess |= DELETE; + break; + } + + // + // slightly new scheme - the redir isn't automatically loaded anymore. We + // may perform a named pipe operation before VDMREDIR is loaded. So now we + // load VDMREDIR.DLL if the filespec designates a named pipe + // + + if (IsNamedPipeName(lpFileName)) { + if (!LoadVdmRedir()) { + goto errorReturn; + } + ItsANamedPipe = TRUE; + + // + // convert \\<this_computer>\PIPE\foo\bar\etc to \\.\PIPE\... + // if we already allocated a buffer for the slash conversion use + // that else this call will allocate another buffer (we don't + // want to write over DOS memory) + // + + lpFileName = VrConvertLocalNtPipeName(dupFileName, lpFileName); + if (!lpFileName) { + goto errorReturn; + } + } + + // + // open the file. If we think its a named pipe then use FILE_FLAG_OVERLAPPED + // because the client might use DosReadAsyncNmPipe or DosWriteAsyncNmPipe + // and the only way to accomplish that is to open the named pipe handle in + // overlapped I/O mode now + // + + // sudeepb 26-Apr-1993 We are retrying opening the file in case + // of failure without GENERIC_WRITE because of the incompatibility + // of DOS and NT CD ROM driver. DOS CDROM driver ignores the write + // bit which we have to fakeout in this way. + + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + IsFirst = TRUE; + + while (TRUE) { + if ((hFile = CreateFileOem(lpFileName, + dwDesiredAccess, + dwShareMode, + &sa, + OPEN_EXISTING, + ItsANamedPipe ? FILE_FLAG_OVERLAPPED : 0, + NULL)) == (HANDLE)-1){ + if (IsFirst && dwDesiredAccess & GENERIC_WRITE && + IsCdRomFile(lpFileName)) { + dwDesiredAccess &= ~GENERIC_WRITE; + IsFirst = FALSE; + continue; + } + +errorReturn: + + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + if (dupFileName) { + free(dupFileName); + } else if (ItsANamedPipe && lpFileName) { + LocalFree(lpFileName); + } + return; + } + else + break; + } + + // + // we have to keep some info around when we open a named pipe + // + + if (ItsANamedPipe) { + VrAddOpenNamedPipeInfo(hFile, lpFileName); + setDX(1); + } + else { + if(((dwFileSize=GetFileSize(hFile,&dwSizeHigh)) == (DWORD)-1) || + dwSizeHigh) { + CloseHandle (hFile); + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + setCX ((USHORT)dwFileSize); + setBX ((USHORT)(dwFileSize >> 16 )); + setDX(0); + } + + setBP((USHORT)hFile); + setAX((USHORT)((ULONG)hFile >> 16)); + setCF(0); + if (dupFileName) { + free(dupFileName); + } else if (ItsANamedPipe) { + LocalFree(lpFileName); + } + return; +} + +#define DEM_CREATE 0 +#define DEM_CREATE_NEW 1 + +/* demCreate - Create a file + * + * + * Entry - Client (DS:SI) Full path of File + * Client (CX) Attributes + * 00 - Normal File + * 01 - Read-only file + * 02 - Hidden File + * 04 - System file + * + * Exit + * SUCCESS + * Client (CY) = 0 + * Client (AX) = Assigned Open Handle (high word) + * VSF(BP) = Assigned Open Handle (low word) + * + * FAILURE + * CY = 1 + * AX = error code + * HARD ERROR + * CY = 1 + * AX = 0FFFFh + * + */ + +VOID demCreate (VOID) +{ + demCreateCommon (DEM_CREATE); + return; +} + +/* demCreateNew - Create a New file + * + * + * Entry - Client (DS:SI) Full path of File + * Client (CX) Attributes + * 00 - Normal File + * 01 - Read-only file + * 02 - Hidden File + * 04 - System file + * + * Exit + * SUCCESS + * Client (CY) = 0 + * Client (AX) = Assigned Open Handle (high word) + * VSF(BP) = Assigned Open Handle (low word) + * + * FAILURE + * CY = 1 + * AX = error code + * HARD ERROR + * CY = 1 + * AX = 0FFFFh + * + */ + +VOID demCreateNew (VOID) +{ + demCreateCommon (DEM_CREATE_NEW); + return; +} + +/* demDelete - Delete a file + * + * + * Entry - Client (DS:DX) Full path of File + * + * Exit + * SUCCESS + * Client (CY) = 0 + * + * FAILURE + * CY = 1 + * AX = system status code + * HARD ERROR + * CY = 1 + * AX = 0FFFFh + * + */ + +VOID demDelete (VOID) +{ +LPSTR lpFileName; + + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getDX()); + +#if DBG + if(fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demfile: Deleting File<%s>\n",lpFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + if (DeleteFileOem (lpFileName) == FALSE){ + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + + setCF(0); + return; +} + + +/* demChMod - Change the file modes + * + * Entry - Client (DS:DX) Full path of File + * Client (AL) = 0 Get File Modes 1 Set File Modes + * Client (CL) new modes + * + * Exit + * SUCCESS + * Client (CY) = 0 + * Client (CL) = file attributes in get case. + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = Error Code + * HARD ERROR + * CY = 1 + * AX = 0FFFFh + * + * Compatibility Notes: + * + * ATTR_VOLUME_ID,ATTR_DEVICE and ATTR_DIRECTORY are not supported + * by WIN32 call. Although these are unpublished for DOS world also + * but still a compatibility requirement. + */ + +VOID demChMod (VOID) +{ +LPSTR lpFileName; +DWORD dwAttr; + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getDX()); + +#if DBG + if(fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demfile: ChMod File <%s>\n",lpFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + + if(getAL() == 0){ + if ((dwAttr = GetFileAttributesOem(lpFileName)) == -1) + goto dcerr; + + + if (dwAttr == FILE_ATTRIBUTE_NORMAL) { + dwAttr = 0; + } + else { + dwAttr &= DOS_ATTR_MASK; + } + + setCX((USHORT)dwAttr); + setCF(0); + return; + } + + if((dwAttr = getCX()) == 0) + dwAttr = FILE_ATTRIBUTE_NORMAL; + + dwAttr &= DOS_ATTR_MASK; + if (!SetFileAttributesOem(lpFileName,dwAttr)) + goto dcerr; + + setCF(0); + return; + +dcerr: + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; +} + + +/* demRename - Rename a file + * + * Entry - Client (DS:DX) Source File + * Client (ES:DI) Destination File + * + * Exit + * SUCCESS + * Client (CY) = 0 + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = Error Code + * + */ + +VOID demRename (VOID) +{ +LPSTR lpSrc,lpDst; + + lpSrc = (LPSTR) GetVDMAddr (getDS(),getDX()); + lpDst = (LPSTR) GetVDMAddr (getES(),getDI()); + +#if DBG + if(fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demfile: Rename File <%s> to <%s>\n",lpSrc,lpDst); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + // DOS rename fails accross drives with 11h error code + // This following check is OK even for UNC names and SUBST drives. + // SUBST drives come to NTVDM as env variables for current directory + // and we will treet them just like a network drive and full qualified + // path will be sent from NTDOS. + if(toupper(lpSrc[0]) != toupper(lpDst[0])) { + setCF(1); + setAX(0x11); + return; + } + + // Now check that SRC and DEST are not pointing to the same file. + // if they do return error 5. + if (!_stricmp (lpSrc, lpDst)) { + setCF(1); + setAX(0x5); + return; + } + + if(MoveFileOem(lpSrc,lpDst) == FALSE){ + demClientError(INVALID_HANDLE_VALUE, *lpSrc); + return; + } + + setCF(0); + return; +} + +/* demCreateCommon - Create a file or Craete a new file + * + * + * Entry - flCreateType - DEM_CREATE_NEW create new + * DEM_CREATE create + * + * Exit + * SUCCESS + * Client (CY) = 0 + * Client (AX) = Assigned Open Handle (high word) + * Client (BP) = Assigned Open Handle (low word) + * + * FAILURE + * CY = 1 + * AX = error code + * HARD ERROR + * CY = 1 + * AX = 0FFFFh + * + */ + +VOID demCreateCommon (flCreateType) +ULONG flCreateType; +{ +HANDLE hFile; +LPSTR lpFileName; +LPSTR lpDot; +DWORD dwAttr; +DWORD dwFileSize,dwSizeHigh; +USHORT uErr; +DWORD dwDesiredAccess; +SECURITY_ATTRIBUTES sa; +CHAR cFOTName[MAX_PATH]; +BOOL ttfOnce,IsFirst; +DWORD dwLastError; + + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI()); + dwAttr = (DWORD)getCX(); + + if ((dwAttr & 0xff) == 0) + dwAttr = FILE_ATTRIBUTE_NORMAL; + + /* Special case for set volume label (INT 21 Func 3CH, Attr = 8H */ + + if((flCreateType == DEM_CREATE) && (dwAttr == ATTR_VOLUME_ID)) { + if((uErr = demCreateLabel(lpFileName[DRIVEBYTE], + lpFileName+LABELOFF))) { + setCF(1); + setAX(uErr); + return; + } + setAX(0); + setBP(0); // in this case handle = 0 and if we will + setCF(0); // close this handle CF will be 0(!) + return; + } + + +#if DBG + if(fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demfile: Creating File <%s>\n",lpFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + ttfOnce = TRUE; + IsFirst = TRUE; + + while (TRUE) { + if ((hFile = CreateFileOem(lpFileName, + // create file with delete access and sharing mode + // so that anybody can delete it without closing + // the file handle returned from create file + dwDesiredAccess, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + &sa, + flCreateType == DEM_CREATE ? CREATE_ALWAYS : CREATE_NEW, + dwAttr, + NULL)) == (HANDLE)-1){ + + if (IsFirst && dwDesiredAccess & GENERIC_WRITE && + IsCdRomFile(lpFileName)) { + dwDesiredAccess &= ~GENERIC_WRITE; + IsFirst = FALSE; + continue; + } + + // APP COMPATABILITY + // Some WOW apps installing .TTF or .FON or Fonts fail to create + // The file because the font is already open by GDI32 server. + // The Stupid install/setup programs don't gracefully handle + // this error, they bomb out of the install with retry or cancel + // without offering the user a way to ignore the error (which + // would be the right thing since the font already exists. + // To work around this problem we do a RemoveFontResource here + // which causes GDI32 to unmap the file, we then retry + // the create. - mattfe june 93 + + // If it is a TTF file then we need to remove the font resource + // for the .FOT file of the same name + + if (ttfOnce) { + + // Look for the file extension + + lpDot = strrchr(lpFileName,'.'); + + if (lpDot) { + if ( (!_strcmpi(lpDot,".TTF")) || + (!_strcmpi(lpDot,".FON")) || + (!_strcmpi(lpDot,".FOT")) ) { + + if ( RemoveFontResourceOem(lpFileName) ) { + PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); + ttfOnce = FALSE; + continue; + } + + // We failed to remove the .TTF file probably because + // the .FOT file was loaded, so try to remove it + + if (!_strcmpi(lpDot,".TTF")) { + + RtlZeroMemory(cFOTName,sizeof(cFOTName)); + RtlCopyMemory(cFOTName,lpFileName,(ULONG)lpDot-(ULONG)lpFileName); + strcat(cFOTName,".FOT"); + if ( RemoveFontResourceOem(cFOTName) ) { + PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); + ttfOnce = FALSE; + continue; + } + } + } + } + } + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + else + break; + } + + if((dwFileSize=GetFileSize(hFile,&dwSizeHigh) == -1) || dwSizeHigh) { + CloseHandle (hFile); + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + return; + } + setCX ((USHORT)dwFileSize); + setBX ((USHORT)(dwFileSize >> 16 )); + setBP((USHORT)hFile); + setAX((USHORT)((ULONG)hFile >> 16)); + setCF(0); + return; +} + +BOOL IsCdRomFile (PSTR pszPath) +{ + UCHAR pszRootDir[MAX_PATH]; + UCHAR file_system[MAX_PATH]; + int i, j; + + // The given path is either a network path or has D: at the start. + + if (!pszPath[0]) { + return FALSE; + } + + if (pszPath[1] == ':') { + pszRootDir[0] = pszPath[0]; + pszRootDir[1] = ':'; + pszRootDir[2] = '\\'; + pszRootDir[3] = 0; + } else if (IS_ASCII_PATH_SEPARATOR(pszPath[0]) && + IS_ASCII_PATH_SEPARATOR(pszPath[1])) { + j = 0; + for (i = 2; pszPath[i]; i++) { + if (IS_ASCII_PATH_SEPARATOR(pszPath[i])) { + if (++j == 2) { + break; + } + } + } + memcpy(pszRootDir, pszPath, i); + pszRootDir[i] = '\\'; + pszRootDir[i+1] = 0; + } else { + return FALSE; + } + + if (GetVolumeInformationOem(pszRootDir, NULL, 0, NULL, NULL, NULL, + file_system, MAX_PATH) && + !_stricmp(file_system, "CDFS")) { + + return TRUE; + } + + return FALSE; +} + +/* demCheckPath - Check path (for device only) + * + * + * Entry - Client (DS:SI) Full path (with last '\') + * + * Exit + * SUCCESS + * Client (CF) = 0 + * + * FAILURE + * CF = 1 + */ + +VOID demCheckPath (VOID) +{ +HANDLE hFile; +LPSTR lpFileName; +CHAR cDRV; +CHAR szFileName[MAX_PATH]; + + lpFileName = (LPSTR) GetVDMAddr (getDS(),getSI()); + cDRV = getDL()+'A'-1; + + setDX(0); + + // If we have \dev dir then return OK, DOS always has this directory for + // devices. + + if(!lstrcmpi(lpFileName, "\\DEV\\")) { + setCF(0); + return; + } + + sprintf(szFileName, "%c:%sNUL", cDRV, lpFileName); + +#if DBG + if(fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demfile: Check Pathe <%s>\n",lpFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + + // If path exists then we always can open NUL file in this directory, + // if path doesn't exists then CreateFile returns INVALID_HANDLE_VALUE + // + + if ((hFile = CreateFileOem((LPSTR) szFileName, + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + + demClientError(INVALID_HANDLE_VALUE, *lpFileName); + + setCF(1); + return; + } + + CloseHandle (hFile); + setCF(0); + + return; +} + + +PDOSSFT GetFreeSftEntry(PDOSSF pSfHead, PWORD usSFN) +{ + WORD i; + PDOSSFT pSft; + DWORD ulSFLink; + + *usSFN = 0; + for (;;) { + + pSft = (PDOSSFT) &(pSfHead->SFTable); + for (i = 0; i < pSfHead->SFCount; i++) { + if (pSft[i].SFT_Ref_Count == 0) { + *usSFN += i; + return (pSft + i); + } + } + *usSFN += pSfHead->SFCount; + + ulSFLink = pSfHead->SFLink; + if (ulSFLink & 0xFFFF == 0xFFFF) { + break; + } + + pSfHead = (PDOSSF) Sim32GetVDMPointer (ulSFLink, 0, 0); + } + + return NULL; +} + + +/** VDDAllocateDosHandle - Allocates an unused DOS file handle. + * + * ENTRY - + * IN pPDB - OPTIONAL: (16:16) address of the PDB for the task + * OUT ppSFT - OPTIONAL: Returns a 32-bit flat pointer to the SFT + * associated with the allocated file handle. + * OUT ppJFT - OPTIONAL: Returns a 32-bit flat pointer to the JFT + * associated with the given PDB. + * + * + * EXIT + * SUCCESS - Returns the value of the DOS file handle and associated + * pointers. + * FAILURE - Returns a negative value. The absolute value of this number + * is the DOS error code. + * + * Comments: + * This routine searches for an unused DOS file handle and SFT and "opens" + * a file. After the successful completion of this call, the returned file + * handle and the corresponding SFT will be reserved for the caller's use, and + * will be unavailable to other callers trying to issue DOS Open or Create api + * calls. It is the caller's responsibility to release this file handle (with + * a call to VDDReleaseDosHandle). + * + * If the pPDB pointer is not supplied (e.g., is NULL), then the current + * PDB as reported by DOS will be used. + * + * Although the ppSFT parameter is technically optional, it is a required + * parameter of the VDDAssociateNtHandle call. This was done to avoid a + * second handle lookup in the Associate call. + * + */ + +SHORT VDDAllocateDosHandle (pPDB,ppSFT,ppJFT) +ULONG pPDB; +PDOSSFT* ppSFT; +PBYTE* ppJFT; +{ +PDOSPDB pPDBFlat; +PBYTE pJFT; +PDOSSFT pSFT; +USHORT usSFN; +WORD JFTLength; +SHORT hDosHandle; + + if (!pPDB) { + pPDB = (ULONG) (*pusCurrentPDB) << 16; + } + + // + // Get the JFT. + // + + pPDBFlat = (PDOSPDB) Sim32GetVDMPointer (pPDB, 0, 0); + pJFT = (PBYTE) Sim32GetVDMPointer (pPDBFlat->PDB_JFN_Pointer, 0, 0); + + + // + // Check to see if there's a free entry in the JFT. + // + + JFTLength = pPDBFlat->PDB_JFN_Length; + for (hDosHandle = 0; hDosHandle < JFTLength; hDosHandle++) { + if (pJFT[hDosHandle] == 0xFF) { + break; + } + } + + // If no room in the JFT then return ERROR_TOO_MANY_OPEN_FILES + + if (hDosHandle == JFTLength) { + return (- ERROR_TOO_MANY_OPEN_FILES); + } + + // + // Check the SF for a free SFT. + // + + if (!(pSFT = GetFreeSftEntry(pSFTHead, &usSFN))) { + return (- ERROR_TOO_MANY_OPEN_FILES); + } + + pJFT[hDosHandle] = (BYTE)usSFN; + RtlZeroMemory((PVOID)pSFT, sizeof(DOSSFT)); + pSFT->SFT_Ref_Count = 1; + + if (ppSFT) { + *ppSFT = (pSFT); + } + + if (ppJFT) { + *ppJFT = pJFT; + } + + return(hDosHandle); + +} + +/** VDDAssociateNtHandle - Associates the passed NT handle and access flags + * the given DOS handle. + * + * ENTRY - + * IN pSFT - flat address of the SFT to be updated + * IN hFile32 - NT handle to be stored + * IN wAccess - access flags to set in the SFT + * + * EXIT - + * This routine has no return value. + * + * Comments: + * This routine takes the passed NT handle value and stores it in a DOS SFT + * so that it can later be retrieved by the VDDRetrieveNtHandle api. The + * pointer to the SFT is returned by the VDDAllocateDosHandle api. + * + * The format of the third parameter is the same as the file access flags + * defined for DOS Open File with Handle call (Int 21h, func 3dh), documented + * in Microsoft MS-DOS Programmer's Reference. Only the low order byte of + * this parameter is used, the upper byte is reserved and must be zero. + * The value of this parameter is placed into the passed SFT. This is provided + * to allow the caller to define the access rights for the corresponding + * DOS file handle. + * + */ + +VOID VDDAssociateNtHandle (pSFT,hFile,wAccess) +PDOSSFT pSFT; +HANDLE hFile; +WORD wAccess; +{ + + pSFT->SFT_Mode = wAccess&0x7f; // take out no_inherit bit + pSFT->SFT_Attr = 0; // Not used. + pSFT->SFT_Flags = (wAccess&0x80) ? 0x1000 : 0; // copy no_inherit bit. + pSFT->SFT_Devptr = (ULONG) -1; + pSFT->SFT_NTHandle = (ULONG) hFile; + +} + + +/** VDDReleaseDosHandle - Release the given DOS file handle. + * + * ENTRY - + * IN pPDB - OPTIONAL: (16:16) address of the PDB for the task + * IN hFile - DOS handle (in low byte) + * + * EXIT - + * TRUE - the file handle was released + * FALSE - The file handle was not valid or open + * + * Comments: + * This routine updates the DOS file system data areas to free the passed + * file handle. No effort is made to determine if this handle was previously + * opened by the VDDAllocateDosHandle call. It is the responsibility of the + * caller to insure that the given file handle in the specified PDB should + * be closed. + * + * If the pPDB pointer is not supplied (e.g., is NULL), then the current + * PDB as reported by DOS will be used. + * + */ + +BOOL VDDReleaseDosHandle (pPDB,hFile) +ULONG pPDB; +SHORT hFile; +{ +PBYTE pJFT; +PDOSSFT pSFT; +HANDLE ntHandle; + + + if (!pPDB) { + pPDB = (ULONG) (*pusCurrentPDB) << 16; + } + + ntHandle = VDDRetrieveNtHandle(pPDB,hFile,(PVOID *)&pSFT,&pJFT); + if (!ntHandle) { + return(FALSE); + } + + pJFT[hFile] = 0xFF; + + // Decrement reference count. + + pSFT->SFT_Ref_Count--; + + return(TRUE); + +} + + +/** VDDRetrieveNtHandle - Given a DOS file handle get the associated + * NT handle. + * + * ENTRY - + * IN pPDB - OPTIONAL: (16:16) address of the PDB for the task + * IN hFile - DOS handle (in low byte) + * OUT ppSFT - OPTIONAL: Returns a 32-bit flat pointer to the SFT + * associated with the given file. + * OUT ppJFT - OPTIONAL: Returns a 32-bit flat pointer to the JFT + * associated with the given PDB. + * + * + * EXIT - + * SUCCESS - returns 4byte NT handle + * FAILURE - returns 0 + * + * Comments: + * The value returned by this function will be the NT handle passed in a + * previous VDDAssociateNtHandle call. If no previous call is made to the + * the Associate api, then the value returned by this function is undefined. + * + * If the pPDB pointer is not supplied (e.g., is NULL), then the current + * PDB as reported by DOS will be used. + * + * Although the ppSFT parameter is technically optional, it is a required + * parameter of the VDDAssociateNtHandle call. This was done to avoid a + * second handle lookup in the Associate call. + * + * The third and fourth parameters are provided to provide the caller the + * ability to update the DOS system data areas directly. This may be useful + * for performance reasons, or necessary depending on the application. In + * general, care must be taken when using these pointers to avoid causing + * system integrity problems. + * + */ + +HANDLE VDDRetrieveNtHandle (pPDB,hFile,ppSFT,ppJFT) +ULONG pPDB; +SHORT hFile; +PDOSSFT* ppSFT; +PBYTE* ppJFT; +{ +PDOSPDB pPDBFlat; +PDOSSF pSfFlat; +PDOSSFT pSftFlat; +PBYTE pJFT; +USHORT usSFN; +USHORT usSFTCount; +ULONG ulSFLink; + + if (!pPDB) { + pPDB = (ULONG) (*pusCurrentPDB) << 16; + } + + // Get flat pointer to PDB + pPDBFlat = (PDOSPDB) Sim32GetVDMPointer(pPDB, 0, 0); + + // Check that handle is within JFT + if (hFile >= pPDBFlat->PDB_JFN_Length) { + return 0; + } + + // Get the pointer to JFT + pJFT = (PBYTE) Sim32GetVDMPointer (pPDBFlat->PDB_JFN_Pointer, 0, 0); + + // Get the SFN, remember -1 indicates unused JFT + usSFN = (USHORT) pJFT[hFile]; + if (usSFN == 0xff) { + return 0; + } + + // Get flat pointer to SF + pSfFlat = pSFTHead; + + // Find the right SFT group + while (usSFN >= (usSFTCount = pSfFlat->SFCount)){ + usSFN = usSFN - usSFTCount; + ulSFLink = pSfFlat->SFLink; + if (ulSFLink & 0xffff == 0xffff) + return 0; + pSfFlat = (PDOSSF) Sim32GetVDMPointer (ulSFLink, 0, 0); + } + + // Get the begining of SFT + + pSftFlat = (PDOSSFT)&(pSfFlat->SFTable); + + // Get the SFN, Finally + if(pSftFlat[usSFN].SFT_Ref_Count == 0) { + return 0; + } + + if (ppSFT) { + *ppSFT = (pSftFlat + usSFN); + } + + if (ppJFT) { + *ppJFT = pJFT; + } + + return (HANDLE) pSftFlat[usSFN].SFT_NTHandle; +} diff --git a/private/mvdm/dos/dem/demgset.c b/private/mvdm/dos/dem/demgset.c new file mode 100644 index 000000000..511867cae --- /dev/null +++ b/private/mvdm/dos/dem/demgset.c @@ -0,0 +1,1013 @@ +/* demgset.c - Drive related SVC hanlers. + * + * demSetDefaultDrive + * demGetBootDrive + * demGetDriveFreeSpace + * demGetDrives + * demGSetMediaID + * demQueryDate + * demQueryTime + * demSetDate + * demSetTime + * demSetDTALocation + * demGSetMediaID + * demGetDPB + + * Modification History: + * + * Sudeepb 02-Apr-1991 Created + * + */ +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> +#include <mvdm.h> +#include <winbase.h> +#include "demdasd.h" + +#define BOOTDRIVE_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Setup" +#define BOOTDRIVE_VALUE "BootDir" + + +#define SUCCESS 0 +#define NODISK 1 +#define FAILURE 2 +BYTE demGetDpbI(BYTE Drive, DPB UNALIGNED *pDpb); + + +UCHAR PhysicalDriveTypes[26]={0}; + +extern PDOSSF pSFTHead; + +USHORT nDrives = 0; +CHAR IsAPresent = TRUE; +CHAR IsBPresent = TRUE; + +/* demSetDefaultDrive - Set the default drive + * + * + * Entry - Client (DL) Drive to be set + * Client (DS:SI) Current Directory on that drive + * + * Exit - SUCCESS + * Client (CY) = 0 + * Current Drive Set + * + * FAILURE + * Client (CY) = 1 + * Current Drive Not Set + * + * + * Notes: + * Unlike DOS/CRUISER NT just keeps one current directory for a thread. + * So here this routine gets the drive to be set default as well as + * the current direcotry on that drive and NT does the job in one shot. + */ + +VOID demSetDefaultDrive (VOID) +{ +LPSTR lpPath; + + lpPath = (LPSTR)GetVDMAddr (getDS(),getSI()); + + if(*(PCHAR)lpPath != (CHAR)(getDL()+'A')){ + demPrintMsg(MSG_DEFAULT_DRIVE); + setCF(1); + setAX(1); + return; + } + + if (SetCurrentDirectoryOem (lpPath) == FALSE){ + demClientError(INVALID_HANDLE_VALUE, *lpPath); + return; + } + + setCF(0); + return; +} + +/* demGetBootDrive - Get the boot drive + * + * + * Entry - None + * + * Exit - CLIENT (AL) has 1 base boot drive (i.e. C=3) + * + * We try to read the registry value that indicates the real boot drive. This + * should be the location of autoexec.bat, etc. If we can't find the key, + * or if the value indicates some drive letter that is not a fixed drive, + * then we use a fallback plan of just saying drive C. + * + */ + +VOID demGetBootDrive (VOID) +{ + HKEY hKey; + DWORD retCode; + DWORD dwType, cbData = MAX_PATH; + CHAR szBootDir[MAX_PATH]; + BYTE Drive = 3; // default it to 'C:' + + retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + BOOTDRIVE_PATH, + 0, + KEY_EXECUTE, // Requesting read access. + &hKey); + + + if (retCode) { + // error: can't find section + goto DefaultBootDrive; + } + + retCode = RegQueryValueEx(hKey, + BOOTDRIVE_VALUE, + NULL, + &dwType, + szBootDir, + &cbData); + + RegCloseKey(hKey); + + if (retCode) { + // error: can't find key + goto DefaultBootDrive; + } + + if (GetDriveType(szBootDir) != DRIVE_FIXED) { + // error: drive is not a valid boot drive + goto DefaultBootDrive; + } + + Drive = (BYTE)(tolower(szBootDir[0])-'a')+1; + +DefaultBootDrive: + + setAL(Drive); + return; + +} + +/* demGetDriveFreeSpace - Get free Space on the drive + * + * + * Entry - Client (AL) Drive in question + * 0 - A: etc. + * + * Exit - + * SUCCESS + * Client (CY) = 0 + * Client (AL) = FAT ID byte + * Client (BX) = Number of free allocation units + * Client (CX) = Sector size + * Client (DX) = Total Number of allocation units on disk + * Client (SI) = Sectors per allocation unit + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = Error code + */ + + +VOID demGetDriveFreeSpace (VOID) +{ +WORD SectorsPerCluster; +WORD BytesPerSector; +WORD FreeClusters; +WORD TotalClusters; + +BYTE Drive; +PBDS pbds; + + + Drive = getAL(); + if (demGetDiskFreeSpace(Drive, + &BytesPerSector, + &SectorsPerCluster, + &TotalClusters, + &FreeClusters) == FALSE) + { + demClientError(INVALID_HANDLE_VALUE, (CHAR)(getAL() + 'A')); + return; + } + + if (pbds = demGetBDS(Drive)) { + // if the device is a floppy, reload its bpb + if (!(pbds->Flags & NON_REMOVABLE) && !demGetBPB(pbds)) + pbds->bpb.MediaID = 0xF8; + + setAL(pbds->bpb.MediaID); + } + else + setAL(0); + + setBX(FreeClusters); + setCX(BytesPerSector); + setDX(TotalClusters); + setSI(SectorsPerCluster); + setCF(0); + return; +} + + +// +// retrieves drive type for physical drives +// substd, redir drives are returned as unknown +// uses same DriveType definitions as win32 GetDriveTypeW +// +UCHAR +demGetPhysicalDriveType( + UCHAR DriveNum) +{ + return DriveNum < 26 ? PhysicalDriveTypes[DriveNum] : DRIVE_UNKNOWN; +} + + + + +// +// worker function for DemGetDrives +// +UCHAR GetPhysicalDriveType(UCHAR DriveNum) +{ + + NTSTATUS Status; + HANDLE Handle; + UCHAR uchRet; + OBJECT_ATTRIBUTES Obja; + IO_STATUS_BLOCK IoStatusBlock; + OEM_STRING OemString; + UNICODE_STRING UniString; + UNICODE_STRING FileName; + FILE_FS_DEVICE_INFORMATION DeviceInfo; + CHAR RootName[] = "A:\\"; + WCHAR wRootName[sizeof(RootName)*sizeof(WCHAR)]; + + OemString.Buffer = RootName; + OemString.Length = sizeof(RootName) - 1; + OemString.MaximumLength = sizeof(RootName); + UniString.Buffer = wRootName; + UniString.MaximumLength = sizeof(wRootName); + + RootName[0] = 'A' + DriveNum; + Status = RtlOemStringToUnicodeString(&UniString,&OemString,FALSE); + if (!NT_SUCCESS(Status) || + !RtlDosPathNameToNtPathName_U(wRootName, &FileName, NULL, NULL) ) + { + return DRIVE_UNKNOWN; + } + + uchRet = DRIVE_UNKNOWN; + InitializeObjectAttributes(&Obja, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + // + // Open the file, excluding directories + // + FileName.Length -= sizeof(WCHAR); + Status = NtOpenFile( + &Handle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &Obja, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + + // subst drives are not physical drives (actually dirs) + if (!NT_SUCCESS(Status)) { + goto GPDExitClean; + } + + // + // Determine if this is a network or disk file system. If it + // is a disk file system determine if this is removable or not + // + + Status = NtQueryVolumeInformationFile( + Handle, + &IoStatusBlock, + &DeviceInfo, + sizeof(DeviceInfo), + FileFsDeviceInformation + ); + + NtClose(Handle); + if (!NT_SUCCESS(Status) || + DeviceInfo.Characteristics & FILE_REMOTE_DEVICE) + { + goto GPDExitClean; + } + + switch ( DeviceInfo.DeviceType ) { + + case FILE_DEVICE_CD_ROM: + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + uchRet = DRIVE_CDROM; + break; + + case FILE_DEVICE_VIRTUAL_DISK: + uchRet = DRIVE_RAMDISK; + break; + + case FILE_DEVICE_DISK: + case FILE_DEVICE_DISK_FILE_SYSTEM: + uchRet = DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA + ? DRIVE_REMOVABLE : DRIVE_FIXED; + break; + } + +GPDExitClean: + RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer); + + return uchRet; +} + + + + +/* demGetDrives - Get number of logical drives in the system + * called by ntdos from msinit to get numio + * initializes the physical drive list, which consists + * of drive types for true physical drives. subst + * and redir drives are classed as DRIVE_UNKNOWN. + * + * Entry - None + * + * Exit - + * SUCCESS + * Client (CY) = 0 + * Client (AL) = number of drives + * + * FAILURE + * None + */ + +VOID demGetDrives (VOID) +{ + UCHAR DriveType; + UCHAR DriveNum; + char RootName[]="?:\\"; + BOOL bCounting; + + // + // Initialize the local drive list with Drive type + // + DriveNum = 0; + + // + // Use win32 for A and B, to prevent the fs from trying to + // read floppy drives. Make a special check for subst drives + // which get returned as DRIVE_FIXED. (subst drives don't qualify + // as physical drives). + // + do { + + RootName[0] = 'A' + DriveNum; + DriveType = GetDriveTypeOem(RootName); + + switch (DriveType) { + case DRIVE_NO_ROOT_DIR: + case DRIVE_REMOTE: + DriveType = DRIVE_UNKNOWN; + break; + + case DRIVE_FIXED: // check for substd drive ... + DriveType = GetPhysicalDriveType(DriveNum); + break; + } + + PhysicalDriveTypes[DriveNum] = DriveType; + + } while (++DriveNum < 2); + + + // if A doesn't exist means b also doesn't exist + DriveType = PhysicalDriveTypes[0]; + if (DriveType == DRIVE_UNKNOWN) { + IsAPresent = FALSE; + IsBPresent = FALSE; + } + + DriveType = PhysicalDriveTypes[1]; + if (DriveType == DRIVE_UNKNOWN) { + IsBPresent = FALSE; + } + + nDrives = 2; + bCounting = TRUE; + + do { + DriveType = GetPhysicalDriveType(DriveNum); + + RootName[0] = 'A' + DriveNum; + + PhysicalDriveTypes[DriveNum] = DriveType; + if (bCounting) { + if (DriveType == DRIVE_REMOVABLE || + DriveType == DRIVE_FIXED || + DriveType == DRIVE_CDROM || + DriveType == DRIVE_RAMDISK ) + { + nDrives++; + } + else { + bCounting = FALSE; + } + } + + } while (++DriveNum < 26); + + setAX(nDrives); + setCF(0); + return; +} + + +/* demQueryDate - Get The Date + * + * + * Entry - None + * + * Exit - + * SUCCESS + * Client (DH) - month + * Client (DL) - Day + * Client (CX) - Year + * Client (AL) - WeekDay + * + * FAILURE + * Never + */ + +VOID demQueryDate (VOID) +{ +SYSTEMTIME TimeDate; + + GetLocalTime(&TimeDate); + setDH((UCHAR)TimeDate.wMonth); + setDL((UCHAR)TimeDate.wDay); + setCX(TimeDate.wYear); + setAL((UCHAR)TimeDate.wDayOfWeek); + return; +} + + +/* demQueryTime - Get The Time + * + * + * Entry - None + * + * Exit - + * SUCCESS + * Client (CH) - hour + * Client (CL) - minutes + * Client (DH) - seconds + * Client (DL) - hundredth of seconds + * + * FAILURE + * Never + */ + +VOID demQueryTime (VOID) +{ +SYSTEMTIME TimeDate; + + GetLocalTime(&TimeDate); + setCH((UCHAR)TimeDate.wHour); + setCL((UCHAR)TimeDate.wMinute); + setDH((UCHAR)TimeDate.wSecond); + setDL((UCHAR)(TimeDate.wMilliseconds/10)); + return; +} + + +/* demSetDate - Set The Date + * + * + * Entry - Client (CX) - Year + * Client (DH) - month + * Client (DL) - Day + * + * Exit - SUCCESS + * Client (AL) - 00 + * + * + * FAILURE + * Client (AL) - ff + */ + +VOID demSetDate (VOID) +{ +SYSTEMTIME TimeDate; + + GetLocalTime(&TimeDate); + TimeDate.wYear = (WORD)getCX(); + TimeDate.wMonth = (WORD)getDH(); + TimeDate.wDay = (WORD)getDL(); + if(SetLocalTime(&TimeDate) || GetLastError() == ERROR_PRIVILEGE_NOT_HELD) + setAL(0); + else + setAL(0xff); +} + + +/* demSetTime - Set The Time + * + * + * Entry - Client (CH) - hour + * Client (CL) - minutes + * Client (DH) - seconds + * Client (DL) - hundredth of seconds + * + * Exit - None + * + */ + +VOID demSetTime (VOID) +{ +SYSTEMTIME TimeDate; + + GetLocalTime(&TimeDate); + TimeDate.wHour = (WORD)getCH(); + TimeDate.wMinute = (WORD)getCL(); + TimeDate.wSecond = (WORD)getDH(); + TimeDate.wMilliseconds = (WORD)getDL()*10; + if (SetLocalTime(&TimeDate) || GetLastError() == ERROR_PRIVILEGE_NOT_HELD) + setAL(0); + else + setAL(0xff); +} + + +/* demSetDTALocation - Set The address of variable where Disk Transfer Address + * is stored in NTDOS. + * + * + * Entry - Client (DS:AX) - DTA variable Address + * Client (DS:DX) - CurrentPDB address + * + * Exit - None + * + */ + +VOID demSetDTALocation (VOID) +{ + PDOSWOWDATA pDosWowData; + + pulDTALocation = (PULONG) GetVDMAddr(getDS(),getAX()); + pusCurrentPDB = (PUSHORT) GetVDMAddr(getDS(),getDX()); + pExtendedError = (PDEMEXTERR) GetVDMAddr(getDS(),getCX()); + + pDosWowData = (PDOSWOWDATA) GetVDMAddr(getDS(),getSI()); + pSFTHead = (PDOSSF) GetVDMAddr(getDS(),(WORD)pDosWowData->lpSftAddr); + return; +} + + +/* demGSetMediaID - Get or set volume serial and volume label + * + * Entry - Client (BL) - Drive Number (0=A;1=B..etc) + * Client (AL) - Get or Set (0=Get;1=Set) + * Client (DS:DX) - Buffer to return information + * (see VOLINFO in dosdef.h) + * + * Exit - SUCCESS + * Client (CF) - 0 + * + * FAILURE + * Client (CF) - 1 + * Client (AX) - Error code + * + * NOTES: + * Currently There is no way for us to set Volume info. + */ + +VOID demGSetMediaID (VOID) +{ +CHAR Drive; +PVOLINFO pVolInfo; + + // Set Volume info is not currently supported + if(getAL() != 0){ + setCF(1); + return; + } + + pVolInfo = (PVOLINFO) GetVDMAddr (getDS(),getDX()); + Drive = (CHAR)getBL(); + + if (!GetMediaId(Drive, pVolInfo)) { + demClientError(INVALID_HANDLE_VALUE, (CHAR)(Drive + 'A')); + return; + } + + setCF(0); + return; +} + +// +// GetMediaId +// +// +BOOL +GetMediaId( + CHAR DriveNum, + PVOLINFO pVolInfo + ) +{ +CHAR RootPathName[] = "?:\\"; +CHAR achVolumeName[NT_VOLUME_NAME_SIZE]; +CHAR achFileSystemType[MAX_PATH]; +DWORD adwVolumeSerial[2],i; + + + + // Form Root path + RootPathName[0] = DriveNum + 'A'; + + // Call the supreme source of information + if(!GetVolumeInformationOem( RootPathName, + achVolumeName, + NT_VOLUME_NAME_SIZE, + adwVolumeSerial, + NULL, + NULL, + achFileSystemType, + MAX_PATH) ) + { + return FALSE; + } + + // Fill in user buffer. Remember to convert the null characters + // to spaces in different strings. + + STOREDWORD(pVolInfo->ulSerialNumber,adwVolumeSerial[0]); + + strncpy(pVolInfo->VolumeID,achVolumeName,DOS_VOLUME_NAME_SIZE); + for(i=0;i<DOS_VOLUME_NAME_SIZE;i++) { + if (pVolInfo->VolumeID[i] == '\0') + pVolInfo->VolumeID[i] = '\x020'; + } + + strncpy(pVolInfo->FileSystemType,achFileSystemType,FILESYS_NAME_SIZE); + for(i=0;i<FILESYS_NAME_SIZE;i++) { + if (pVolInfo->FileSystemType[i] == '\0') + pVolInfo->VolumeID[i] = '\x020'; + } + + + return TRUE; +} + + + + + + + + + + + +/* demGetDPB - Get Devicr Parameter Block + * + * Entry - Client (AL) - Drive Number (0=A;1=B..etc) + * Client (DS:DI) - Buffer to return information + * + * Exit - SUCCESS + * Client (CF) - 0 + * + * FAILURE + * Client (CF) - 1 + * Client (AX) - Error code + * + */ +VOID demGetDPB(VOID) +{ +BYTE Drive; +DPB UNALIGNED *pDPB; +BYTE Result; + + Drive = getAL(); + pDPB = (PDPB) GetVDMAddr(getDS(), getDI()); + + Result = demGetDpbI(Drive, pDPB); + if (Result == FAILURE) { + demClientError(INVALID_HANDLE_VALUE,(CHAR)(Drive + 'A')); + return; + } + else if (Result == NODISK){ + setCF(1); + return; + } + setAX(0); + setCF(0); +} + +/* demGetDPBI - Worker for GetDPB and GetDPBList + * + * Entry - + * Drive -- Drive Number (0=A;1=B..etc) + * pDPB -- pointer to the location to store the dpb + * + * Exit - SUCCESS + * returns success, fills in DPB + * FAILURE + * returns FAILURE or NODISK + */ +BYTE demGetDpbI(BYTE Drive, DPB UNALIGNED *pDPB) +{ + WORD SectorSize, ClusterSize, FreeClusters, TotalClusters; + PBDS pbds; + WORD DirsPerSector; + + if (demGetDiskFreeSpace(Drive, + &SectorSize, + &ClusterSize, + &TotalClusters, + &FreeClusters + )) + { + pDPB->Next = (PDPB) 0xFFFFFFFF; + pDPB->SectorSize = SectorSize; + pDPB->FreeClusters = FreeClusters; + pDPB->MaxCluster = TotalClusters + 1; + pDPB->ClusterMask = ClusterSize - 1; + pDPB->ClusterShift = 0; + pDPB->DriveNum = pDPB->Unit = Drive; + while ((ClusterSize & 1) == 0) { + ClusterSize >>= 1; + pDPB->ClusterShift++; + } + if (pbds = demGetBDS(Drive)) { + // if the device is a floppy, reload its bpb + if (!(pbds->Flags & NON_REMOVABLE) && !demGetBPB(pbds)) { + return NODISK; + } + pDPB->MediaID = pbds->bpb.MediaID; + pDPB->FATSector = pbds->bpb.ReservedSectors; + pDPB->FATs = pbds->bpb.FATs; + pDPB->RootDirs = pbds->bpb.RootDirs; + pDPB->FATSize = pbds->bpb.FATSize; + pDPB->DirSector = pbds->bpb.FATs * pbds->bpb.FATSize + + pDPB->FATSector; + DirsPerSector = pDPB->SectorSize >> DOS_DIR_ENTRY_LENGTH_SHIFT_COUNT; + pDPB->FirstDataSector = pDPB->DirSector + + ((pDPB->RootDirs + DirsPerSector - 1) / + DirsPerSector); + pDPB->DriveAddr = 0x123456; + pDPB->FirstAccess = 10; + } + // if we don't know the drive, fake a DPB for it + else { + + pDPB->MediaID = 0xF8; + pDPB->FATSector = 1; + pDPB->FATs = 2; + pDPB->RootDirs = 63; + pDPB->FATSize = 512; + pDPB->DirSector = 1; + pDPB->DriveAddr = 1212L * 64L * 1024L + 1212L; + pDPB->FirstAccess = 10; + } + return SUCCESS; + } + else { + return FAILURE; + } +} + +/* demGetComputerName - Get computer name + * + * Entry - + * Client (DS:DX) - 16 byte buffer + * + * Exit - Always Succeeds + * DS:DX is filled with the computer name (NULL terminated). + */ + +VOID demGetComputerName (VOID) +{ +PCHAR pDOSBuffer; +CHAR ComputerName[MAX_COMPUTERNAME_LENGTH+1]; +DWORD BufferSize = MAX_COMPUTERNAME_LENGTH+1; +ULONG i; + + pDOSBuffer = (PCHAR) GetVDMAddr(getDS(), getDX()); + + if (GetComputerNameOem(ComputerName, &BufferSize)){ + if (BufferSize <= 15){ + for (i = BufferSize ; i < 15 ; i++) + ComputerName [i] = ' '; + ComputerName[15] = '\0'; + strcpy (pDOSBuffer, ComputerName); + } + else{ + strncpy (pDOSBuffer, ComputerName, 15); + pDOSBuffer [15] = '\0'; + } + setCX(0x1ff); + } + else { + *pDOSBuffer = '\0'; + setCH(0); + } +} + +#define APPS_SPACE_LIMIT 999990*1024 //999990kb to be on the safe side + +BOOL demGetDiskFreeSpace( + BYTE Drive, + WORD * BytesPerSector, + WORD * SectorsPerCluster, + WORD * TotalClusters, + WORD * FreeClusters +) +{ +CHAR chRoot[]="?:\\"; +DWORD dwBytesPerSector; +DWORD dwSectorsPerCluster; +DWORD dwTotalClusters; +DWORD dwFreeClusters; +DWORD dwLostFreeSectors; +DWORD dwLostTotalSectors; +DWORD dwNewSectorPerCluster; +ULONG ulTotal,ulTemp; + + // sudeepb 22-Jun-1993; + // Please read this routine with an empty stomach. + // The most common mistake all the apps do when calculating total + // disk space or free space is to neglect overflow. Excel/Winword/Ppnt + // and lots of other apps use "mul cx mul bx" never taking care + // of first multiplication which can overflow. Hence this routine makes + // sure that first multiplication will never overflow by fixing + // appropriate values. Secondly, all these above apps use signed long + // to deal with these free spaces. This puts a limit of 2Gb-1 on + // the final outcome of the multiplication. If its above this the setup + // fails. So here we have to make sure that total should never exceed + // 0x7fffffff. Another bug in above setup program's that if you return + // anything more than 999,999KB then they try to put "999,999KB+\0", but + // unfortunately the buffer is only 10 bytes. Hence it corrupts something + // with the last byte. In our case that is low byte of a segment which + // it later tries to pop and GPF. This shrinks the maximum size that + // we can return is 999,999KB. + + chRoot[0]=(CHAR)('A'+ Drive); + + if (GetDiskFreeSpaceOem(chRoot, + &dwSectorsPerCluster, + &dwBytesPerSector, + &dwFreeClusters, + &dwTotalClusters) == FALSE) + return FALSE; + + /* + * HPFS and NTFS can give num clusters over dos limit + * For these cases increase SectorPerCluster and lower + * cluster number accordingly. If the disk is very large + * even this isn't enuf, so pass max sizes that dos can + * handle. + * + * The following algorithm is accurate within 1 cluster + * (final figure) + * + */ + dwLostFreeSectors = dwLostTotalSectors = 0; + while (dwTotalClusters + dwLostTotalSectors/dwSectorsPerCluster > 0xFFFF) + { + if (dwSectorsPerCluster > 0x7FFF) + { + dwTotalClusters = 0xFFFF; + if (dwFreeClusters > 0xFFFF) + dwFreeClusters = 0xFFFF; + break; + } + + if (dwFreeClusters & 1) { + dwLostFreeSectors += dwSectorsPerCluster; + } + if (dwTotalClusters & 1) { + dwLostTotalSectors += dwSectorsPerCluster; + } + dwSectorsPerCluster <<= 1; + dwFreeClusters >>= 1; + dwTotalClusters >>= 1; + } + + if (dwTotalClusters < 0xFFFF) { + dwFreeClusters += dwLostFreeSectors/dwSectorsPerCluster; + dwTotalClusters += dwLostTotalSectors/dwSectorsPerCluster; + } + + if ((dwNewSectorPerCluster = (0xffff / dwBytesPerSector)) < dwSectorsPerCluster) + dwSectorsPerCluster = dwNewSectorPerCluster; + + // finally check for 999,999kb + ulTemp = (ULONG)((USHORT)dwSectorsPerCluster * (USHORT)dwBytesPerSector); + + // check that total space does'nt exceed 999,999kb + ulTotal = ulTemp * (USHORT)dwTotalClusters; + + if (ulTotal > APPS_SPACE_LIMIT){ + if (ulTemp <= APPS_SPACE_LIMIT) + dwTotalClusters = APPS_SPACE_LIMIT / ulTemp; + else + dwTotalClusters = 1; + } + + ulTotal = ulTemp * (USHORT)dwFreeClusters; + + if (ulTotal > APPS_SPACE_LIMIT) { + if (ulTemp <= APPS_SPACE_LIMIT) + dwFreeClusters = APPS_SPACE_LIMIT / ulTemp; + else + dwFreeClusters = 1; + } + + *BytesPerSector = (WORD) dwBytesPerSector; + *SectorsPerCluster = (WORD) dwSectorsPerCluster; + *TotalClusters = (WORD) dwTotalClusters; + *FreeClusters = (WORD) dwFreeClusters; + return TRUE; +} + +/* demGetDPBList - Create the list of dpbs + * + * Entry - + * Client(ES:BP) - points to destination for the dpb list + * Exit - SUCCESS + * Client (BP) - points to first byte past dpb list + * FAILURE + * Client (BP) unchanged + * + * Notes: + * For performance reasons, only the drive and unit fields are + * filled in. The only application I know of that depends on the + * dpb list is go.exe (a shareware app installer). Even if we filled + * in the other fields they would likely be incorrect when the app + * looked at them, since ntdos.sys never updates the pdbs in the pdb + * list + */ +VOID demGetDPBList (VOID) +{ + UCHAR DriveType; + UCHAR DriveNum; + DPB UNALIGNED *pDpb; + USHORT usDpbOffset, usDpbSeg; + + usDpbOffset = getBP(); + usDpbSeg = getES(); + pDpb = (PDPB)GetVDMAddr(usDpbSeg, usDpbOffset); + + // + // Iterate over all of the drive letters. + // + DriveNum = 0; + do { + DriveType = demGetPhysicalDriveType(DriveNum); + + // + // Only include the local non cd rom drives ?? ramdisk ??? + // + if ((DriveType == DRIVE_REMOVABLE) || (DriveType == DRIVE_FIXED)) { + + // + // Fake the Dpb for the drive + // + pDpb->DriveNum = pDpb->Unit = DriveNum; + + // + // Link it to the next dpb + // + usDpbOffset += sizeof(DPB); + pDpb->Next = (PDPB)(((ULONG)usDpbSeg) << 16 | usDpbOffset); + + // + // Advance to the next dpb + // + pDpb += 1; + + ASSERT(usDpbOffset < 0xFFFF); + } + + } while (++DriveNum < 26); + + // + // Terminate the list if necessary + // + if (usDpbOffset != getBP()) { + pDpb -= 1; + pDpb->Next = (PDPB)-1; + } + + // + // Return the new free space pointer + // + setBP(usDpbOffset); +} diff --git a/private/mvdm/dos/dem/demhndl.c b/private/mvdm/dos/dem/demhndl.c new file mode 100644 index 000000000..7d6fd5045 --- /dev/null +++ b/private/mvdm/dos/dem/demhndl.c @@ -0,0 +1,605 @@ +/* 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. + * + * 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; +} + + +/* 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; +} + +/* 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); +} diff --git a/private/mvdm/dos/dem/demioctl.c b/private/mvdm/dos/dem/demioctl.c new file mode 100644 index 000000000..00999f273 --- /dev/null +++ b/private/mvdm/dos/dem/demioctl.c @@ -0,0 +1,583 @@ +/* demioctl.c - SVC handlers for DOS IOCTL calls + * + * demIOCTL + * + * Modification History: + * + * Sudeepb 23-Apr-1991 Created + * + */ + +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> +#include <winbase.h> +#include "demdasd.h" + +PFNSVC apfnSVCIoctl [] = { + demIoctlInvalid, // IOCTL_GET_DEVICE_INFO 0 + demIoctlInvalid, // IOCTL_SET_DEVICE_INFO 1 + demIoctlInvalid, // IOCTL_READ_HANDLE 2 + demIoctlInvalid, // IOCTL_WRITE_HANDLE 3 + demIoctlInvalid, // IOCTL_READ_DRIVE 4 + demIoctlInvalid, // IOCTL_WRITE_DRIVE 5 + demIoctlInvalid, // IOCTL_GET_INPUT_STATUS 6 + demIoctlInvalid, // IOCTL_GET_OUTPUT_STATUS 7 + demIoctlChangeable, // IOCTL_CHANGEABLE 8 + demIoctlChangeable, // IOCTL_DeviceLocOrRem 9 + demIoctlInvalid, // IOCTL_HandleLocOrRem a + demIoctlInvalid, // IOCTL_SHARING_RETRY b + demIoctlInvalid, // GENERIC_IOCTL_HANDLE c + demIoctlDiskGeneric, // GENERIC_IOCTL d + demIoctlInvalid, // IOCTL_GET_DRIVE_MAP e + demIoctlInvalid, // IOCTL_SET_DRIVE_MAP f + demIoctlInvalid, // IOCTL_QUERY_HANDLE 10 + demIoctlDiskQuery, // IOCTL_QUERY_BLOCK 11 + demIoctlInvalid + +}; + +MEDIA_TYPE MediaForFormat; + +#define MAX_IOCTL_INDEX (sizeof (apfnSVCIoctl) / sizeof (PFNSVC)) + + +/* demIOCTL - DOS IOCTLS + * + * + * Entry - depends on the subfunction. See dos\ioctl.asm + * + * Exit + * SUCCESS + * Client (CY) = 0 + * for other registers see the corresponding function header + * + * FAILURE + * Client (CY) = 1 + * for other registers see the corresponding function header + */ + +VOID demIOCTL (VOID) +{ +ULONG iIoctl; + + iIoctl = (ULONG) getAL(); + +#if DBG + if (iIoctl >= MAX_IOCTL_INDEX){ + setAX((USHORT) ERROR_INVALID_FUNCTION); + setCF(1); + return; + } +#endif + + (apfnSVCIoctl [iIoctl])(); + + return; +} + +/* demIoctlChangeable - Is drive removeable (subfunc 8) or remote (subfunc 9) + * + * + * Entry - Client (AL) - subfunc + * Client (BL) - drive number (a=0,b=1 etc) + * + * Exit + * SUCCESS + * Client (CY) = 0 + * if subfunc 8 + * AX = 0 if removeable media + * AX = 1 otherwise + * if subfunc 9 + * DX = 0 if not remote + * DX = 1000 if remote + * + * FAILURE + * Client (CY) = 1 + * Client (AX) = error code + * + * CDROM drives are considered remote drives with write protection + * by dos. (full support requires a VDD) + */ + +VOID demIoctlChangeable (VOID) +{ +ULONG ulSubFunc; + +CHAR RootPathName[] = "?:\\"; +DWORD DriveType; +UCHAR DriveNum; + + ulSubFunc = getAL(); + + // Form Root path + DriveNum = getBL(); + DriveType = demGetPhysicalDriveType(DriveNum); + if (DriveType == DRIVE_UNKNOWN) { + RootPathName[0] = (CHAR)('A' + DriveNum); + DriveType = GetDriveTypeOem(RootPathName); + } + + if (DriveType == DRIVE_UNKNOWN || DriveType == DRIVE_NO_ROOT_DIR){ + setAX (ERROR_INVALID_DRIVE); + setCF(1); + return; + } + + if (ulSubFunc == IOCTL_CHANGEABLE){ + if(DriveType == DRIVE_REMOVABLE) + setAX(0); + else + setAX(1); // includes CDROM drives + } + else { + setAL(0); + if (DriveType == DRIVE_REMOTE || DriveType == DRIVE_CDROM) + setDX(0x1000); + else + // We have to return 800 rather then 0 as Dos Based Quatrro pro + // behaves very badly if this bit is not set. sudeepb 15-Jun-1994 + setDX(0x800); + } + setCF(0); + return; + +} + + + +/* demIoctlDiskGeneric - Block device generic ioctl + * + * + * Entry - Client (BL) = drive number (a=0;b=1 etc) + * (CL) = subfucntion code + * (SI:DX) pointer to parameter block. + * Exit + * SUCCESS + * Client (CY) = 0 + * (AX) = 0 + * parameter block updated + * FAILURE + * Client (CY) = 1 + * (AX) = error code + */ + +VOID demIoctlDiskGeneric (VOID) + +{ + BYTE Code, Drive; + PDEVICE_PARAMETERS pdms; + PMID pmid; + PRW_BLOCK pRW; + PFMT_BLOCK pfmt; + PBDS pbds; + DWORD Head, Cylinder; + DWORD TrackSize; + DWORD Sectors, StartSector; + BYTE BootSector[BYTES_PER_SECTOR]; + PBOOTSECTOR pbs; + PBPB pBPB; + PACCESSCTRL pAccessCtrl; + WORD SectorSize, ClusterSize, TotalClusters, FreeClusters; + + Code = getCL(); + Drive = getBL(); + + if (Code == IOCTL_GETMEDIA) { + pmid = (PMID) GetVDMAddr(getSI(), getDX()); + if (!GetMediaId(Drive, (PVOLINFO)pmid)) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + } + else { + setAX(0); + setCF(0); + } + + return; + } + + + + // if we don't know the drive, bail out + if((pbds = demGetBDS(Drive)) == NULL && Code != IOCTL_GETDPM) { + if (!demIsDriveFloppy(Drive)) + host_direct_access_error(NOSUPPORT_HARDDISK); + setAX(DOS_FILE_NOT_FOUND); + setCF(1); + return; + } + switch (Code) { + case IOCTL_SETDPM: + + pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX()); + if (!(pdms->Functions & ONLY_SET_TRACKLAYOUT)) { + pbds->FormFactor = pdms->DeviceType; + pbds->Cylinders = pdms->Cylinders; + pbds->Flags = pdms->DeviceAttrs; + pbds->MediaType = pdms->MediaType; + if (pdms->Functions & INSTALL_FAKE_BPB) { + pbds->Flags |= RETURN_FAKE_BPB; + pbds->bpb = pdms->bpb; + // update the total sectors, we need it + // for verification + pbds->TotalSectors = (pbds->bpb.Sectors) ? + pbds->bpb.Sectors : + pbds->bpb.BigSectors; + } + else { + pbds->Flags &= ~RETURN_FAKE_BPB; + pbds->rbpb = pdms->bpb; + } + } + MediaForFormat = Unknown; + if (!(pbds->Flags & NON_REMOVABLE)){ + nt_floppy_close(pbds->DrivePhys); + } + else { + nt_fdisk_close(pbds->DrivePhys); + } + break; + + case IOCTL_WRITETRACK: + + pRW = (PRW_BLOCK) GetVDMAddr(getSI(), getDX()); + Sectors = pRW->Sectors; + StartSector = pRW->StartSector; + StartSector += pbds->bpb.TrackSize * + (pRW->Cylinder * pbds->bpb.Heads + pRW->Head); + Sectors = demDasdWrite(pbds, + StartSector, + Sectors, + pRW->BufferOff, + pRW->BufferSeg + ); + if (Sectors != pRW->Sectors) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + break; + + case IOCTL_FORMATTRACK: + pfmt = (PFMT_BLOCK)GetVDMAddr(getSI(), getDX()); + Head = pfmt->Head; + Cylinder = pfmt->Cylinder; + if ((pbds->Flags & NON_REMOVABLE) && + pfmt->Head < pbds->bpb.Heads && + pfmt->Cylinder < pbds->Cylinders) + { + if (pfmt->Functions == STATUS_FOR_FORMAT){ + pfmt->Functions = 0; + setCF(0); + return; + } + if (!demDasdFormat(pbds, Head, Cylinder, NULL)) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + } + else { + if (MediaForFormat == Unknown) { + demDasdFormat(pbds, + Head, + Cylinder, + &MediaForFormat + ); + } + if (pfmt->Functions & STATUS_FOR_FORMAT){ + if (MediaForFormat == Unknown) + pfmt->Functions = 2; // illegal combination + else + pfmt->Functions = 0; + break; + } + if (MediaForFormat == Unknown || + !demDasdFormat(pbds, Head, Cylinder, &MediaForFormat)) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + } + break; + + case IOCTL_SETMEDIA: + pmid = (PMID) GetVDMAddr(getSI(), getDX()); + + if (pbds->Flags & NON_REMOVABLE) { + Sectors = nt_fdisk_read(pbds->DrivePhys, + 0, + BYTES_PER_SECTOR, + BootSector + ); + } + else { + if (demGetBPB(pbds)) + Sectors = nt_floppy_read(pbds->DrivePhys, + 0, + BYTES_PER_SECTOR, + BootSector + ); + else + Sectors = 0; + } + pbs = (PBOOTSECTOR) BootSector; + if (Sectors != BYTES_PER_SECTOR || + pbs->ExtBootSig != EXT_BOOTSECT_SIG) + { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + pbs->SerialNum = pmid->SerialNum; + pbs->Label = pmid->Label; + pbs->FileSysType = pmid->FileSysType; + if (pbds->Flags & NON_REMOVABLE) { + Sectors = nt_fdisk_write(pbds->DrivePhys, + 0, + BYTES_PER_SECTOR, + (PBYTE)pbs + ); + nt_fdisk_close(pbds->DrivePhys); + } + else { + Sectors = nt_floppy_write(pbds->DrivePhys, + 0, + BYTES_PER_SECTOR, + (PBYTE) pbs + ); + nt_floppy_close(pbds->DrivePhys); + } + if (Sectors != BYTES_PER_SECTOR) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + break; + + + // ioctl get device parameters + case IOCTL_GETDPM: + pdms = (PDEVICE_PARAMETERS)GetVDMAddr(getSI(), getDX()); + // if we couldn't find the bds, fake one + if (pbds == NULL) { + HANDLE hVolume; + CHAR achRoot[]="\\\\.\\?:"; + DISK_GEOMETRY DiskGM; + DWORD SizeReturned; + + if (!demGetDiskFreeSpace(Drive, + &SectorSize, + &ClusterSize, + &TotalClusters, + &FreeClusters + )){ + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + + achRoot[4] = Drive + 'A'; + + hVolume = CreateFileA(achRoot, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (hVolume == INVALID_HANDLE_VALUE) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + if (!DeviceIoControl(hVolume, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGM, + sizeof(DISK_GEOMETRY), + &SizeReturned, + NULL + )) { + CloseHandle(hVolume); + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + CloseHandle(hVolume); + Sectors = DiskGM.Cylinders.LowPart * + DiskGM.TracksPerCylinder * + DiskGM.SectorsPerTrack; + pdms->DeviceType = FF_FDISK; + pdms->DeviceAttrs = NON_REMOVABLE; + pdms->MediaType = 0; + pdms->bpb.SectorSize = SectorSize; + pdms->bpb.ClusterSize = (BYTE) ClusterSize; + pdms->bpb.ReservedSectors = 1; + pdms->bpb.FATs = 2; + pdms->bpb.RootDirs = (Sectors > 32680) ? 512 : 64; + pdms->bpb.MediaID = 0xF8; + pdms->bpb.TrackSize = (WORD) DiskGM.SectorsPerTrack; + pdms->bpb.Heads = (WORD) DiskGM.TracksPerCylinder; + pdms->Cylinders = (WORD) DiskGM.Cylinders.LowPart; + if (Sectors >= 40000) { + TrackSize = 256 * ClusterSize + 2; + pdms->bpb.FATSize = (WORD) ((Sectors - pdms->bpb.ReservedSectors + - pdms->bpb.RootDirs * 32 / 512 + + TrackSize - 1 ) / TrackSize); + } + else { + pdms->bpb.FATSize = (WORD) (((Sectors / ClusterSize) * 3 / 2) / + 512 + 1); + } + pdms->bpb.HiddenSectors = Sectors; + Sectors = TotalClusters * ClusterSize; + if (Sectors >= 0x10000) { + pdms->bpb.Sectors = 0; + pdms->bpb.BigSectors = Sectors; + } + else { + pdms->bpb.Sectors = (WORD) Sectors; + pdms->bpb.BigSectors = 0; + } + pdms->bpb.HiddenSectors -= Sectors; + break; + } + pdms->DeviceType = pbds->FormFactor; + pdms->DeviceAttrs = pbds->Flags & ~(HAS_CHANGELINE); + pdms->Cylinders = pbds->Cylinders; + pdms->MediaType = 0; + if (pdms->Functions & BUILD_DEVICE_BPB){ + if (!(pbds->Flags & NON_REMOVABLE) && + !demGetBPB(pbds)) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + pBPB = &pbds->bpb; + } + else + // copy recommended bpb + pBPB = &pbds->rbpb; + + pdms->bpb = *pBPB; + break; + + case IOCTL_READTRACK: + pRW = (PRW_BLOCK) GetVDMAddr(getSI(), getDX()); + Sectors = pRW->Sectors; + StartSector = pRW->StartSector; + StartSector += pbds->bpb.TrackSize * + (pRW->Cylinder * pbds->bpb.Heads + pRW->Head); + Sectors = demDasdRead(pbds, + StartSector, + Sectors, + pRW->BufferOff, + pRW->BufferSeg + ); + + if (Sectors != pRW->Sectors) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + break; + + case IOCTL_VERIFYTRACK: + pfmt = (PFMT_BLOCK) GetVDMAddr(getSI(), getDX()); + if(!demDasdVerify(pbds, pfmt->Head, pfmt->Cylinder)) { + setAX(demWinErrorToDosError(GetLastError())); + setCF(1); + return; + } + break; + + case IOCTL_GETACCESS: + pAccessCtrl = (PACCESSCTRL) GetVDMAddr(getSI(), getDX()); + pAccessCtrl->AccessFlag = (pbds->Flags & UNFORMATTED_MEDIA) ? + 0 : 1; + break; + case IOCTL_SETACCESS: + pAccessCtrl = (PACCESSCTRL) GetVDMAddr(getSI(), getDX()); + pbds->Flags &= ~(UNFORMATTED_MEDIA); + if (pAccessCtrl->AccessFlag == 0) + pAccessCtrl->AccessFlag |= UNFORMATTED_MEDIA; + break; + + default: + setAX(DOS_INVALID_FUNCTION); + setCF(1); + return; + } + setAX(0); + setCF(0); +} + +/* demIoctlDiskQuery - Query block device generic ioctl capability + * + * + * Entry - Client (BL) = drive number (a=0;b=1 etc) + * (CL) = generic ioctl subfuntion to be queried + * Exit + * SUCCESS + * Client (CY) = 0 + * The specific ioctl is supported + * FAILURE + * Client (CY) = 1 + * The given ioctl is not supported + */ + +VOID demIoctlDiskQuery (VOID) +{ + BYTE Code, Drive; + + Code = getCL(); + Drive = getBL(); + if (demGetBDS(Drive) == NULL) { + setAX(DOS_FILE_NOT_FOUND); + setCF(1); + return; + } + switch (Code) { + + case IOCTL_SETDPM: + case IOCTL_WRITETRACK: + case IOCTL_FORMATTRACK: + case IOCTL_SETMEDIA: + case IOCTL_GETDPM: + case IOCTL_READTRACK: + case IOCTL_VERIFYTRACK: + case IOCTL_GETMEDIA: +// case IOCTL_GETACCESS: +// case IOCTL_SETACCESS: + setAX(0); + setCF(0); + break; + default: + setAX(DOS_ACCESS_DENIED); + setCF(1); + break; + } +} + + +/* demIoctlInvalid - For those subfunctions which may be implemented later + * + * + * Entry - + * + * Exit + * Client (CY) = 1 + * Client (AX) = error_invalid_function + */ + + +VOID demIoctlInvalid (VOID) +{ + setCF(1); + setAX(ERROR_INVALID_FUNCTION); + return; +} diff --git a/private/mvdm/dos/dem/demlabel.c b/private/mvdm/dos/dem/demlabel.c new file mode 100644 index 000000000..26e0e0ffc --- /dev/null +++ b/private/mvdm/dos/dem/demlabel.c @@ -0,0 +1,76 @@ +/* demlabel.c - functions for working this volume labels. + * + * demDeleteLabel() + * demCreateLabel() + * + * Modification History: + * + * YST 1-Feb-1993 Created + * + */ + +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> + +#include <winbase.h> + +USHORT demDeleteLabel(BYTE Drive) +{ + CHAR szStr[32]; + + + sprintf(szStr, "%c:\\", Drive); + + if(!SetVolumeLabelA(szStr, NULL)) + return(1); + else + return(0); +} + + +USHORT demCreateLabel(BYTE Drive, LPSTR lpszName) +{ + CHAR szStr[32]; + CHAR szAnsi[32]; + CHAR szTmp[32]; + CHAR *p, *s; + int i = 0; + + + sprintf(szStr, "%c:\\", Drive); + + s = lpszName; + p = szTmp; + + while(s) { + if(*s != '.') { + *p = *s; + i++; + p++; + } + else { + while(i < 8) { + *p++ = ' '; + i++; + } + } + s++; + + if(i > 11) + break; + } + + szTmp[i] = '\0'; + + OemToAnsi(szTmp, szAnsi); + + if(!SetVolumeLabelA(szStr, szAnsi)) + return(1); + + else + return(0); + + +} diff --git a/private/mvdm/dos/dem/demlock.c b/private/mvdm/dos/dem/demlock.c new file mode 100644 index 000000000..0b35f5d34 --- /dev/null +++ b/private/mvdm/dos/dem/demlock.c @@ -0,0 +1,62 @@ +/* demlock.c - SVC handler for file file locking calls + * + * demLockOper + * + * Modification History: + * + * Sudeepb 07-Aug-1992 Created + */ + +#include "dem.h" +#include "demmsg.h" + +#include <softpc.h> + +/* demLockOper - Lock or Unlock the file data + * + * Entry Client(AX) : Lock = 0 Unlock = 1 + * Client(BX:BP) : NT Handle + * Client(CX:DX) : offset in the file + * Client(SI:DI) : Data Length to be locked + * Exit + * SUCCESS: Client CF = 0 + * FAILURE: Client CF = 1 + */ + +VOID demLockOper (VOID) +{ +HANDLE hFile; +DWORD dwFileOffset,cbLock; + + // Collect all the parameters + hFile = GETHANDLE(getBX(),getBP()); + dwFileOffset = GETULONG (getCX(),getDX()); + cbLock = GETULONG (getSI(),getDI()); + + if(getAL() == 0){ // Locking case + if (LockFile (hFile, + dwFileOffset, + 0, + cbLock, + 0 + ) == TRUE) { + setCF (0); + return; + } + } + else { + if (UnlockFile (hFile, + dwFileOffset, + 0, + cbLock, + 0 + ) == TRUE) { + setCF (0); + return; + } + } + + // Operation failed + demClientError(hFile, (CHAR)-1); + return; +} diff --git a/private/mvdm/dos/dem/demmisc.c b/private/mvdm/dos/dem/demmisc.c new file mode 100644 index 000000000..4ef8e9f3b --- /dev/null +++ b/private/mvdm/dos/dem/demmisc.c @@ -0,0 +1,644 @@ +/* demmisc.c - Misc. SVC routines + * + * demLoadDos + * + * Modification History: + * + * Sudeepb 31-Mar-1991 Created + */ + +#include "dem.h" +#include "demmsg.h" +// #include "demdasd.h" + +#include <stdio.h> +#include <string.h> +#include <softpc.h> +#include <mvdm.h> +#include <dbgsvc.h> +#include <nt_vdd.h> + + +#if DEVL +// int 21h func names +// index off of function number in ah +char *scname[] = { + "Terminate Program", + "Read Kbd with Echo", + "Display Character", + "Auxillary Input", + "Auxillary Output", + "Print Character", + "Direct Con Output", + "Direct Con Input", + "Read Kbd without Echo", + "Display String", + "Read String", + "Check Keyboard Status", + "Flush Buffer,Read Kbd", + "Reset Drive", + "Set Default Drive", + "FCB Open", + "FCB Close", + "FCB Find First", + "FCB Find Next", + "FCB Delete", + "FCB Seq Read", + "FCB Seq Write", + "FCB Create", + "FCB Rename", + "18h??", + "Get Default Drive", + "Set Disk Transfer Addr", + "Get Default Drive Data", + "Get Drive Data", + "1Dh??", + "1Eh??", + "Get Default DPB", + "20h??", + "FCB Random Read", + "FCB Random Write", + "FCB Get File Size", + "FCB Set Random Record", + "Set Interrupt Vector", + "Create Process Data Block", + "FCB Random Read Block", + "FCB Random Write Block", + "FCB Parse File Name", + "Get Date", + "Set Date", + "Get Time", + "Set Time", + "SetReset Write Verify", + "Get Disk Transefr Addr", + "Get Version Number", + "Keep Process", + "Get Drive Parameters", + "GetSet CTRL C", + "Get InDOS Flag", + "Get Interrupt Vector", + "Get Disk Free Space", + "Char Oper", + "GetSet Country Info", + "Make Dir", + "Remove Dir", + "Change DirDir", + "Create File", + "Open File", + "Close File", + "Read File", + "Write File", + "Delete File", + "Move File Ptr", + "GetSet File Attr", + "IOCTL", + "Dup File Handle", + "Force Dup Handle", + "Get Current Dir", + "Alloc Mem", + "Free Mem", + "Realloc Mem", + "Exec Process", + "Exit Process", + "Get Child Process Exit Code", + "Find First", + "Find Next", + "Set Current PSP", + "Get Current PSP", + "Get In Vars", + "Set DPB", + "Get Verify On Write", + "Dup PDB", + "Rename File", + "GetSet File Date and Time", + "Allocation Strategy", + "Get Extended Error", + "Create Temp File", + "Create New File", + "LockUnlock File", + "SetExtendedErrorNetwork-ServerCall", + "Network-UserOper", + "Network-AssignOper", + "xNameTrans", + "PathParse", + "GetCurrentPSP", + "ECS CALL", + "Set Printer Flag", + "Extended Country Info", + "GetSet CodePage", + "Set Max Handle", + "Commit File", + "GetSetMediaID", + "6ah??", + "IFS IOCTL", + "Extended OpenCreate" + }; +#endif + +extern BOOL IsFirstCall; + +extern void nt_floppy_release_lock(void); + +LPSTR pszBIOSDirectory; + +// internal func prototype +BOOL IsDebuggee(void); +void SignalSegmentNotice(WORD wType, + WORD wLoadSeg, + WORD wNewSeg, + LPSTR lpName, + DWORD dwImageLen ); + +/* demLoadDos - Load NTDOS.SYS. + * + * This SVC is made by NTIO.SYS to load NTDOS.SYS. + * + * Entry - Client (DI) - Load Segment + * + * Exit - SUCCESS returns + * FAILURE Kills the VDM + */ +VOID demLoadDos (VOID) +{ +PBYTE pbLoadAddr; +HANDLE hfile; +DWORD BytesRead; + + // get linear address where ntdos.sys will be loaded + pbLoadAddr = (PBYTE) GetVDMAddr(getDI(),0); + + // set up BIOS path string + if(IsDebuggee() && + ((pszBIOSDirectory = (PCHAR)malloc (strlen (pszDefaultDOSDirectory) + + 1 + sizeof("\\ntio.sys") + 1 )) != NULL)) { + strcpy (pszBIOSDirectory, pszDefaultDOSDirectory); + strcat (pszBIOSDirectory,"\\ntio.sys"); + } + + // prepare the dos file name + strcat (pszDefaultDOSDirectory,"\\ntdos.sys"); + + hfile = CreateFileOem(pszDefaultDOSDirectory, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if (hfile == (HANDLE)0xffffffff) { + TerminateVDM(); + } + + BytesRead = 1; + while (BytesRead) { + if (!ReadFile(hfile, pbLoadAddr, 16384, &BytesRead, NULL)) { + TerminateVDM(); + } + pbLoadAddr = (PBYTE)((ULONG)pbLoadAddr + BytesRead); + + } + + CloseHandle (hfile); + + if (!IsDebuggee()) { + free(pszDefaultDOSDirectory); + } + return; +} + + +/* demDOSDispCall + * + * This SVC is made by System_Call upon entering the dos + * + * + * Entry: Client registers as per user app upon entry to dos + * + * Exit - SUCCESS returns, if being debugged and DEMDOSDISP&fShowSvcMsg + * dumps user app's registers and service name + */ +VOID demDOSDispCall(VOID) +{ +#if DEVL + WORD ax; + + if (!IsDebuggee()) { + return; + } + if (fShowSVCMsg & DEMDOSDISP) { + ax = getAX(); + sprintf(demDebugBuffer,"demDosDispCall %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n", + scname[HIBYTE(ax)], + ax,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()+2,getBP()); + + OutputDebugStringOem(demDebugBuffer); + } +#endif +} + + + + +/* demDOSDispRet + * + * This SVC is made by System_Call upon exiting from the dos + * + * Entry: Client registers as per user app upon exit to dos + * + * Exit - SUCCESS returns, if being debugged and DEMDOSDISP&fShowSvcMsg + * dumps user app's registers + */ +VOID demDOSDispRet(VOID) +{ +#if DEVL + PWORD16 pStk; + + if (!IsDebuggee()) { + return; + } + + if (fShowSVCMsg & DEMDOSDISP) { + + // get ptr to flag word on stack + pStk = (WORD *)GetVDMAddr(getSS(), getSP()); + pStk += 2; + + sprintf (demDebugBuffer,"demDosDispRet\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n", + 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=%.1x\n", + getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP(), (*pStk) & 1); + + OutputDebugStringOem(demDebugBuffer); + } +#endif +} + + +/* demEntryDosApp - Dump Entry Point Dos Apps + * + * This SVC is made by NTDOS.SYS,$exec just prior to entering dos app + * + * Entry - Client DS:SI points to entry point + * Client AX:DI points to initial stack + * Client DX has PDB pointer + * + * Exit - SUCCESS returns, if being debugged and DEMDOSAPPBREAK&fShowSvcMsg + * breaks to debugger + */ +VOID demEntryDosApp(VOID) +{ +USHORT PDB; + + PDB = getDX(); + if(!IsFirstCall) + VDDCreateUserHook(PDB); + +#if DEVL + if (!IsDebuggee()) { + return; + } + + if (fShowSVCMsg & DEMDOSAPPBREAK) { + sprintf(demDebugBuffer,"demEntryDosApp: Entry=%.4x:%.4x, Stk=%.4x:%.4x PDB=%.4x\n", + getCS(),getIP(),getAX(),getDI(),PDB); + OutputDebugStringOem(demDebugBuffer); + DebugBreak(); + } +#endif + +} + +/* demLoadDosAppSym - Load Dos Apps Symbols + * + * This SVC is made by NTDOS.SYS,$exec to load Dos App symbols + * + * Entry - Client ES:DI -Fully Qualified Path Name of executable + * Client BX -Load Segment\Reloc Factor + * Client DX:AX -HIWORD:LOWORD exe size + * + * Exit - SUCCESS returns, raises debug exception, if being debugged + * + */ +VOID demLoadDosAppSym(VOID) +{ + + SignalSegmentNotice(DBG_MODLOAD, + getBX(), 0, + (LPSTR)GetVDMAddr(getES(),getDI()), + MAKELONG(getAX(), getDX()) ); + +} + + + +/* demFreeDosAppSym - Free Dos Apps Symbols + * + * This SVC is made by NTDOS.SYS,$exec to Free Dos App symbols + * + * Entry - Client ES:DI -Fully Qualified Path Name of executable + * + * Exit - SUCCESS returns, raises debug exception, if being debugged + * + */ +VOID demFreeDosAppSym(VOID) +{ + + SignalSegmentNotice(DBG_MODFREE, + 0, 0, + (LPSTR)GetVDMAddr(getES(), getDI()), + 0); +} + + +/* demSystemSymbolOp - Manipulate Symbols for special modules + * + * This SVC is made by NTDOS.SYS,NTIO.SYS + * + * Client AH -Operation + * Client AL -module identifier + * Client BX -Load Segment\Reloc Factor + * Client CX:DX -HIWORD:LOWORD exe size + * + * Exit - SUCCESS returns, raises debug exception, if being debugged + * + */ +VOID demSystemSymbolOp(VOID) +{ + + LPSTR pszPathName; + + if (!IsDebuggee()) { + return; + } + switch(getAL()) { + + case ID_NTIO: + pszPathName = pszBIOSDirectory; + break; + case ID_NTDOS: + pszPathName = pszDefaultDOSDirectory; + break; + default: + pszPathName = NULL; + + } + + // check this again for the case where the static strings have been freed + if (pszPathName != NULL) { + + switch(getAH() & (255-SYMOP_CLEANUP)) { + + case SYMOP_LOAD: + SignalSegmentNotice(DBG_MODLOAD, + getBX(), 0, + pszPathName, + MAKELONG(getDX(), getCX()) ); + break; + + case SYMOP_FREE: + //bugbug not implemented yet + break; + + case SYMOP_MOVE: + SignalSegmentNotice(DBG_SEGMOVE, + getBX(), getES(), + pszPathName, + 0); + break; + } + } + + if (getAH() & SYMOP_CLEANUP) { + + if (pszBIOSDirectory != NULL) { + free (pszBIOSDirectory); + } + + if (pszDefaultDOSDirectory != NULL) { + free(pszDefaultDOSDirectory); + } + + } + +} + +VOID demOutputString(VOID) +{ + LPSTR lpText; + UCHAR fPE; + + if ( !IsDebuggee() ) { + return; + } + + fPE = ISPESET; + + lpText = (LPSTR)Sim32GetVDMPointer( + ((ULONG)getDS() << 16) + (ULONG)getSI(), + (ULONG)getBX(), fPE ); + + OutputDebugStringOem( lpText ); +} + +VOID demInputString(VOID) +{ + LPSTR lpText; + UCHAR fPE; + + if ( !IsDebuggee() ) { + return; + } + + fPE = ISPESET; + + lpText = (LPSTR)Sim32GetVDMPointer( + ((ULONG)getDS() << 16) + (ULONG)getDI(), + (ULONG)getBX(), fPE ); + + DbgPrompt( "", lpText, 0x80 ); +} + +/* SignalSegmentNotice + * + * packs up the data and raises STATUS_SEGMENT_NOTIFICATION + * + * Entry - WORD wType - DBG_MODLOAD, DBG_MODFREE + * WORD wLoadSeg - Starting Segment (reloc factor) + * LPSTR lpName - ptr to Name of Image + * DWORD dwModLen - Length of module + * + * + * if wType ==DBG_MODLOAD wOldLoadSeg is unused + * if wType ==DBG_MODFREE wLoadSeg,dwImageLen,wOldLoadSeg are unused + * + * Use 0 or NULL for unused parameters + * + * Exit - void + * + */ +void SignalSegmentNotice(WORD wType, + WORD wLoadSeg, + WORD wNewSeg, + LPSTR lpName, + DWORD dwImageLen ) +{ + int i; + DWORD dw; + LPSTR lpstr; + LPSTR lpModuleName; + char ach[MAX_PATH+9]; // 9 for module name + + if (!IsDebuggee()) { + return; + } + + // create file name + dw = GetFullPathNameOem(lpName, + sizeof(ach)-9, // 9 for module name + ach, + &lpstr); + + if (!dw || dw >= sizeof(ach)) { + lpName = " "; + strcpy(ach, lpName); + } + else { + lpName = lpstr; + } + + // copy in module name + i = 8; // limit len of module name + dw = strlen(ach); + lpModuleName = lpstr = ach+dw+1; + while (*lpName && *lpName != '.' && i--) + { + *lpstr++ = *lpName++; + dw++; + } + *lpstr = '\0'; + dw += 2; + +#if DBG + if (fShowSVCMsg) { + sprintf(demDebugBuffer,"dem Segment Notify: <%s> Seg=%lxh, ImageLen=%ld\n", + ach, (DWORD)wLoadSeg, dwImageLen); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + if (wType == DBG_MODLOAD) { + ModuleLoad(lpModuleName, ach, wLoadSeg, dwImageLen); + } else if (wType == DBG_MODFREE) { + ModuleFree(lpModuleName, ach); + } else if (wType == DBG_SEGMOVE) { + ModuleSegmentMove(lpModuleName, ach, wLoadSeg, wNewSeg); + } +} + + + +/* IsDebuggee + * + * Determines if we are being debugged + * + * Entry: void + * + * Exit: BOOL bRet - TRUE we are being debugged + * + */ +BOOL IsDebuggee(void) +{ + HANDLE MyDebugPort; + DWORD dw; + + // are we being debugged ?? + dw = NtQueryInformationProcess( + NtCurrentProcess(), + ProcessDebugPort, + &MyDebugPort, + sizeof(MyDebugPort), + NULL ); + if (!NT_SUCCESS(dw) || MyDebugPort == NULL) + { + return FALSE; + } + + return TRUE; +} + +/* demIsDebug - Determine if 16bit DOS should make entry/exit calls at int21 + * + * Entry: void + * + * Exit: Client AL = 0 if not + * Client AL = 1 if yes + * + */ +VOID demIsDebug(void) +{ + BYTE dbgflags = 0; + + if (IsDebuggee()) { + dbgflags |= ISDBG_DEBUGGEE; + if (fShowSVCMsg) + dbgflags |= ISDBG_SHOWSVC; + } + + setAL (dbgflags); + return; +} + +/* demDiskReset - Reset floppy disks. + * + * Entry - None + * + * Exit - FDAccess in DOSDATA (NTDOS.SYS) is 0. + */ + +VOID demDiskReset (VOID) +{ + extern WORD * pFDAccess; // defined in SoftPC. + + HostFloppyReset(); + HostFdiskReset(); + *pFDAccess = 0; + + return; +} + +/* demExitVDM - Kill the VDM From 16Bit side with a proper message + * in case something goes wrong. + * + * Entry - DS:SI - Message String + * + * Exit - None (VDM Is killed) + */ + +VOID demExitVDM ( VOID ) +{ + RcErrorDialogBox(ED_BADSYSFILE,"config.nt",NULL); + TerminateVDM (); +} + +/* demWOWFiles - Return what should be the value of files= for WOW VDM. + * + * Entry - AL - files= specified in config.sys + * + * Exit - client AL is set to max if WOW VDM else unmodified + */ + +VOID demWOWFiles ( VOID ) +{ + if(VDMForWOW) + setAL (255); + return; +} diff --git a/private/mvdm/dos/dem/demmsg.c b/private/mvdm/dos/dem/demmsg.c new file mode 100644 index 000000000..cf3161613 --- /dev/null +++ b/private/mvdm/dos/dem/demmsg.c @@ -0,0 +1,48 @@ +/* demmsg.c - debug messages handling for DEM + * + * Modification History + * + * Sudeepb 31-Mar-1991 Created + */ +#if DBG + +#include <stdio.h> +#include <demmsg.h> +#include "dem.h" + +PCHAR aMsg [] = { + "DOS Location Not Found. Using Default.\n", + "Read On NTDOS.SYS Failed.\n", + "Open On NTDOS.SYS Failed.\n", + "EAs Not Supported\n", + "Letter mismatch in Set_Default_Drive\n", + "Volume ID support is missing\n", + "Invalid Date Time Format for NT\n", + "DTA has an Invalid Find Handle for FINDNEXT\n", + "Unexpected failure to get file information\n", + "File Size is too big for DOS\n" +}; + + +/* demPrintMsg - Print Debug Message + * + * Entry - iMsg (Message Index; See demmsg.h) + * + * Exit - None + * + */ + +VOID demPrintMsg (ULONG iMsg) +{ + + if (fShowSVCMsg){ + sprintf(demDebugBuffer,aMsg[iMsg]); + OutputDebugStringOem(demDebugBuffer); + } + + iMsg; + + return; +} + +#endif diff --git a/private/mvdm/dos/dem/demmsg.h b/private/mvdm/dos/dem/demmsg.h new file mode 100644 index 000000000..460039790 --- /dev/null +++ b/private/mvdm/dos/dem/demmsg.h @@ -0,0 +1,18 @@ +/* demmsg.h - debug message numbers for DEM + * + * Modification History + * + * Sudeepb 31-Mar-1991 Created + */ + + +#define MSG_DEFAULTDOS 0 +#define MSG_PARTIALREAD 1 +#define MSG_OPENFAILED 2 +#define MSG_EAS 3 +#define MSG_DEFAULT_DRIVE 4 +#define MSG_VOLID 5 +#define MSG_TIMEDATE 6 +#define MSG_INVALID_HFIND 7 +#define MSG_FILEINFO 8 +#define MSG_FILESIZE_TOOBIG 9 diff --git a/private/mvdm/dos/dem/demsrch.c b/private/mvdm/dos/dem/demsrch.c new file mode 100644 index 000000000..bc99d4d4d --- /dev/null +++ b/private/mvdm/dos/dem/demsrch.c @@ -0,0 +1,2442 @@ +/* demsrch.c - SVC handlers for calls to search files + * + * demFindFirst + * demFindNext + * demFindFirstFCB + * demFindNextFCB + * + * Modification History: + * + * Sudeepb 06-Apr-1991 Created + * + */ + +#include "dem.h" +#include "demmsg.h" +#include "winbasep.h" +#include <vdm.h> +#include <softpc.h> +#include <mvdm.h> +#include <memory.h> +#include <nt_vdd.h> + +extern BOOL IsFirstCall; + + + +/* + * Internal globals, function prototypes + */ + +#define FINDFILE_DEVICE (HANDLE)0xffffffff + +typedef struct _PSP_FILEFINDLIST { + LIST_ENTRY PspFFindEntry; // Next psp + LIST_ENTRY FFindHeadList; // File Find list for this psp + ULONG usPsp; // PSP id +} PSP_FFINDLIST, *PPSP_FFINDLIST; + +typedef struct _FFINDDOSDATA { + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[MAXIMUM_FILENAME_LENGTH + 1]; + FILETIME ftLastWriteTime; + DWORD dwFileSizeLow; + UCHAR uchFileAttributes; + CHAR cFileName[14]; +} FFINDDOSDATA, *PFFINDDOSDATA; + +typedef struct _FILEFINDLIST { + LIST_ENTRY FFindEntry; + ULONG FFindId; + NTSTATUS LastQueryStatus; + LARGE_INTEGER FindFileTics; + HANDLE DirectoryHandle; + PVOID FindBufferBase; + PVOID FindBufferNext; + ULONG FindBufferLength; + FFINDDOSDATA DosData; + USHORT usSrchAttr; + BOOLEAN SupportReset; + UNICODE_STRING PathName; + UNICODE_STRING FileName; +}FFINDLIST, *PFFINDLIST; + +LIST_ENTRY PspFFindHeadList= {&PspFFindHeadList, &PspFFindHeadList}; + + +#define FFINDID_BASE 0x80000000 +ULONG NextFFindId = FFINDID_BASE; +BOOLEAN FFindIdWrap = FALSE; +#define MAX_DIRECTORYHANDLE 64 +#define MAX_FINDBUFFER 128 +ULONG NumDirectoryHandle = 0; +ULONG NumFindBuffer=0; +LARGE_INTEGER FindFileTics = {0,0}; +LARGE_INTEGER NextFindFileTics = {0,0}; + +char szStartDotStar[]="????????.???"; + + +PFFINDLIST +SearchFile( + PWCHAR pwcFile, + USHORT SearchAttr, + PFFINDLIST pFFindEntry, + PFFINDDOSDATA pFFindDDOut + ); + + +NTSTATUS +FileFindNext( + PFFINDDOSDATA pFFindDD, + PFFINDLIST pFFindEntry + ); + +NTSTATUS +FileFindLast( + PFFINDLIST pFFindEntry + ); + +VOID +FileFindClose( + PFFINDLIST pFFindEntry + ); + + +NTSTATUS +FileFindOpen( + PWCHAR pwcFile, + PFFINDLIST pFFindEntry, + ULONG BufferSize + ); + +NTSTATUS +FileFindReset( + PFFINDLIST pFFindEntry + ); + + +HANDLE +FileFindFirstDevice( + PWCHAR FileName, + PFILE_BOTH_DIR_INFORMATION DirectoryInfo + ); + +void +CloseOldestFileFindBuffer( + void + ); + + +BOOL +CopyDirInfoToDosData( + PFFINDDOSDATA pFFindDD, + PFILE_BOTH_DIR_INFORMATION DirectoryInfo, + USHORT SearchAttr + ); + +BOOL +DemOemToUni( + PUNICODE_STRING pUnicode, + LPSTR lpstr + ); + +VOID +FillFcbVolume( + PSRCHBUF pSrchBuf, + CHAR *pFileName, + USHORT SearchAttr + ); + +BOOL +FillDtaVolume( + CHAR *pFileName, + PSRCHDTA pDta, + USHORT SearchAttr + ); + +BOOL +MatchVolLabel( + CHAR * pVolLabel, + CHAR * pBaseName + ); + +VOID +NtVolumeNameToDosVolumeName( + CHAR * pDosName, + CHAR * pNtName + ); + +VOID +FillFCBSrchBuf( + PFFINDDOSDATA pFFindDD, + PSRCHBUF pSrchBuf + ); + +VOID +FillSrchDta( + PFFINDDOSDATA pFFindDD, + PSRCHDTA pDta + ); + +PFFINDLIST +AddFFindEntry( + PWCHAR pwcFile, + PFFINDLIST pFFindEntrySrc + ); + +PPSP_FFINDLIST +GetPspFFindList( + USHORT CurrPsp + ); + +PFFINDLIST +GetFFindEntryByFindId( + ULONG NextFFindId + ); + +VOID +FreeFFindEntry( + PFFINDLIST pFFindEntry + ); + +VOID +FreeFFindList( + PLIST_ENTRY pFFindHeadList + ); + + +/* demFindFirst - Path-Style Find First File + * + * Entry - Client (DS:DX) - File Path with wildcard + * Client (CX) - Search Attributes + * + * Exit - Success + * Client (CF) = 0 + * DTA updated + * + * Failure + * Client (CF) = 1 + * Client (AX) = Error Code + * + * NOTES + * Search Rules: Ignore Read_only and Archive bits. + * If CX == ATTR_NORMAL Search only for normal files + * If CX == ATTR_HIDDEN Search Hidden or normal files + * If CX == ATTR_SYSTEM Search System or normal files + * If CX == ATTR_DIRECTORY Search directory or normal files + * If CX == ATTR_VOLUME_ID Search Volume_ID + * if CX == -1 return everytiing you find + * + * Limitations - 21-Sep-1992 Jonle + * cannot return label from a UNC name,just like dos. + * Apps which keep many find handles open can cause + * serious trouble, we must rewrite so that we can + * close the handles + * + */ + +VOID demFindFirst (VOID) +{ + DWORD dwRet; + PVOID pDta; + + + LPSTR lpFile = (LPSTR) GetVDMAddr (getDS(),getDX()); + + pDta = (PVOID) GetVDMAddr (*((PUSHORT)pulDTALocation + 1), + *((PUSHORT)pulDTALocation)); + + dwRet = demFileFindFirst (pDta, lpFile, getCX()); + + if (dwRet == -1) { + dwRet = GetLastError(); + demClientError(INVALID_HANDLE_VALUE, *lpFile); + return; + } + + if (dwRet != 0) { + setAX((USHORT) dwRet); + setCF (1); + } else { + setCF (0); + } + return; + +} + + +DWORD demFileFindFirst ( + PVOID pvDTA, + LPSTR lpFile, + USHORT SearchAttr) +{ + PSRCHDTA pDta = (PSRCHDTA)pvDTA; + PFFINDLIST pFFindEntry; + FFINDDOSDATA FFindDD; + UNICODE_STRING FileUni; + WCHAR wcFile[MAX_PATH + sizeof(WCHAR)]; + + +#if DBG + if (SIZEOF_DOSSRCHDTA != sizeof(SRCHDTA)) { + sprintf(demDebugBuffer, + "demsrch: FFirst SIZEOF_DOSSRCHDTA %ld != sizeof(SRCHDTA) %ld\n", + SIZEOF_DOSSRCHDTA, + sizeof(SRCHDTA)); + OutputDebugStringOem(demDebugBuffer); + } + + if (fShowSVCMsg & DEMFILIO){ + sprintf(demDebugBuffer,"demsrch: FindFirst<%s>\n", lpFile); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + STOREDWORD(pDta->FFindId,0); + STOREDWORD(pDta->pFFindEntry,0); + + FileUni.Buffer = wcFile; + FileUni.MaximumLength = sizeof(wcFile); + DemOemToUni(&FileUni, lpFile); + + + // + // Do volume label first. + // + if (SearchAttr & ATTR_VOLUME_ID) { + if (FillDtaVolume(lpFile, pDta, SearchAttr)) { + + // got vol label match + // do look ahead before returning + if (SearchAttr != ATTR_VOLUME_ID) { + pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, NULL); + if (pFFindEntry) { + STOREDWORD(pDta->pFFindEntry,pFFindEntry); + STOREDWORD(pDta->FFindId,pFFindEntry->FFindId); + } + } + return 0; + } + + // no vol match, if asking for more than vol label + // fall thru to file search code, otherwise ret error + else if (SearchAttr == ATTR_VOLUME_ID) { + return GetLastError(); + } + } + + // + // Search the dir + // + pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, &FFindDD); + + if (!FFindDD.cFileName[0]) { + + // search.asm in doskrnl never returns ERROR_FILE_NOT_FOUND + // only ERROR_PATH_NOT_FOUND, ERROR_NO_MORE_FILES + DWORD dw; + + dw = GetLastError(); + if (dw == ERROR_FILE_NOT_FOUND) { + SetLastError(ERROR_NO_MORE_FILES); + } + else if (dw == ERROR_BAD_PATHNAME || dw == ERROR_DIRECTORY ) { + SetLastError(ERROR_PATH_NOT_FOUND); + } + return (DWORD)-1; + } + + FillSrchDta(&FFindDD, pDta); + + if (pFFindEntry) { + STOREDWORD(pDta->pFFindEntry,pFFindEntry); + STOREDWORD(pDta->FFindId,pFFindEntry->FFindId); + } + + return 0; +} + + +/* + * DemOemToUni + * + * returns TRUE\FALSE for success, sets last error if fail + * + */ +BOOL DemOemToUni(PUNICODE_STRING pUnicode, LPSTR lpstr) +{ + NTSTATUS Status; + OEM_STRING OemString; + + RtlInitString(&OemString,lpstr); + Status = RtlOemStringToUnicodeString(pUnicode,&OemString,FALSE); + if (!NT_SUCCESS(Status)) { + if (Status == STATUS_BUFFER_OVERFLOW) { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + } + else { + SetLastError(RtlNtStatusToDosError(Status)); + } + return FALSE; + } + + pUnicode->Buffer[pUnicode->Length] = UNICODE_NULL; + + return TRUE; +} + + + + + +/* demFindNext - Path-Style Find Next File + * + * Entry - None + * + * Exit - Success + * Client (CF) = 0 + * DTA updated + * + * Failure + * Client (CF) = 1 + * Client (AX) = Error Code + */ +VOID demFindNext (VOID) +{ + DWORD dwRet; + PVOID pDta; + + pDta = (PVOID) GetVDMAddr(*((PUSHORT)pulDTALocation + 1), + *((PUSHORT)pulDTALocation)); + + dwRet = demFileFindNext (pDta); + + if (dwRet != 0) { + setAX((USHORT) dwRet); + setCF (1); + return; + } + + setCF (0); + return; + +} + + +DWORD demFileFindNext ( + PVOID pvDta) +{ + PSRCHDTA pDta = (PSRCHDTA)pvDta; + USHORT SearchAttr; + PFFINDLIST pFFindEntry; + FFINDDOSDATA FFindDD; + + pFFindEntry = GetFFindEntryByFindId(FETCHDWORD(pDta->FFindId)); + if (!pFFindEntry || + FETCHDWORD(pDta->pFFindEntry) != (DWORD)pFFindEntry ) + { + STOREDWORD(pDta->FFindId,0); + STOREDWORD(pDta->pFFindEntry,0); + + // DOS has only one error (no_more_files) for all causes. + return(ERROR_NO_MORE_FILES); + } + +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "demFileFindNext<%ws>\n", pFFindEntry->PathName.Buffer); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + SearchAttr = pFFindEntry->usSrchAttr; + + // + // Search the dir + // + pFFindEntry = SearchFile(NULL, + SearchAttr, + pFFindEntry, + &FFindDD + ); + + if (!FFindDD.cFileName[0]) { + STOREDWORD(pDta->FFindId,0); + STOREDWORD(pDta->pFFindEntry,0); + return GetLastError(); + } + + FillSrchDta(&FFindDD, pDta); + + if (!pFFindEntry) { + STOREDWORD(pDta->FFindId,0); + STOREDWORD(pDta->pFFindEntry,0); + } + return 0; +} + + + +/* demFindFirstFCB - FCB based Find First file + * + * Entry - Client (DS:SI) - SRCHBUF where the information will be returned + * Client (ES:DI) - Full path file name with possibly wild cards + * Client (Al) - 0 if not an extended FCB + * Client (DL) - Search Attributes + * + * Exit - Success + * Client (CF) = 0 + * SRCHBUF is filled in + * + * Failure + * Client (AL) = -1 + * + * NOTES + * Search Rules: Ignore Read_only and Archive bits. + * If DL == ATTR_NORMAL Search only for normal files + * If DL == ATTR_HIDDEN Search Hidden or normal files + * If DL == ATTR_SYSTEM Search System or normal files + * If DL == ATTR_DIRECTORY Search directory or normal files + * If DL == ATTR_VOLUME_ID Search only Volume_ID + * if DL == -1 return everytiing you find + */ + +VOID demFindFirstFCB (VOID) +{ + LPSTR lpFile; + USHORT SearchAttr; + PSRCHBUF pFCBSrchBuf; + PDIRENT pDirEnt; + PFFINDLIST pFFindEntry; + FFINDDOSDATA FFindDD; + UNICODE_STRING FileUni; + WCHAR wcFile[MAX_PATH]; + + + lpFile = (LPSTR) GetVDMAddr (getES(),getDI()); + +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "demFindFirstFCB<%s>\n", lpFile); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + pFCBSrchBuf = (PSRCHBUF) GetVDMAddr (getDS(),getSI()); + pDirEnt = &pFCBSrchBuf->DirEnt; + + STOREDWORD(pDirEnt->pFFindEntry,0); + STOREDWORD(pDirEnt->FFindId,0); + + + if (getDL() == ATTR_VOLUME_ID) { + FillFcbVolume(pFCBSrchBuf,lpFile, ATTR_VOLUME_ID); + return; + } + + + FileUni.Buffer = wcFile; + FileUni.MaximumLength = sizeof(wcFile); + if (!DemOemToUni(&FileUni ,lpFile)) { + setCF(1); + return; + } + + SearchAttr = getAL() ? getDL() : 0; + pFFindEntry = SearchFile(wcFile, SearchAttr, NULL, &FFindDD); + if (!FFindDD.cFileName[0]){ + demClientError(INVALID_HANDLE_VALUE, *lpFile); + return; + } + + FillFCBSrchBuf(&FFindDD, pFCBSrchBuf); + + if (pFFindEntry) { + STOREDWORD(pDirEnt->pFFindEntry,pFFindEntry); + STOREDWORD(pDirEnt->FFindId,pFFindEntry->FFindId); + } + + setCF(0); + return; +} + + + +/* demFindNextFCB - FCB based Find Next file + * + * Entry - Client (DS:SI) - SRCHBUF where the information will be returned + * Client (Al) - 0 if not an extended FCB + * Client (DL) - Search Attributes + * + * Exit - Success + * Client (CF) = 0 + * SRCHBUF is filled in + * + * Failure + * Client (AL) = -1 + * + * NOTES + * Search Rules: Ignore Read_only and Archive bits. + * If DL == ATTR_NORMAL Search only for normal files + * If DL == ATTR_HIDDEN Search Hidden or normal files + * If DL == ATTR_SYSTEM Search System or normal files + * If DL == ATTR_DIRECTORY Search directory or normal files + * If DL == ATTR_VOLUME_ID Search only Volume_ID + */ + +VOID demFindNextFCB (VOID) +{ + USHORT SearchAttr; + PSRCHBUF pSrchBuf; + PDIRENT pDirEnt; + PFFINDLIST pFFindEntry; + FFINDDOSDATA FFindDD; + + + pSrchBuf = (PSRCHBUF) GetVDMAddr (getDS(),getSI()); + pDirEnt = &pSrchBuf->DirEnt; + + pFFindEntry = GetFFindEntryByFindId(FETCHDWORD(pDirEnt->FFindId)); + if (!pFFindEntry || + FETCHDWORD(pDirEnt->pFFindEntry) != (DWORD)pFFindEntry || + getDL() == ATTR_VOLUME_ID ) + { + if (pFFindEntry && + FETCHDWORD(pDirEnt->pFFindEntry) != (DWORD)pFFindEntry) + { + FreeFFindEntry(pFFindEntry); + } + + STOREDWORD(pDirEnt->pFFindEntry,0); + STOREDWORD(pDirEnt->FFindId,0); + + // DOS has only one error (no_more_files) for all causes. + setAX(ERROR_NO_MORE_FILES); + setCF(1); + return; + } + +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "demFindNextFCB<%ws>\n", pFFindEntry->PathName.Buffer); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + SearchAttr = getAL() ? getDL() : 0; + + // + // Search the dir + // + pFFindEntry = SearchFile(NULL, + SearchAttr, + pFFindEntry, + &FFindDD + ); + + if (!FFindDD.cFileName[0]) { + STOREDWORD(pDirEnt->pFFindEntry,0); + STOREDWORD(pDirEnt->FFindId,0); + setAX((USHORT) GetLastError()); + setCF(1); + } + + FillFCBSrchBuf(&FFindDD, pSrchBuf); + + if (!pFFindEntry) { + STOREDWORD(pDirEnt->FFindId,0); + STOREDWORD(pDirEnt->pFFindEntry,0); + } + + setCF(0); + return; +} + + + +/* demTerminatePDB - PDB Terminate Notification + * + * Entry - Client (BX) - Terminating PDB + * + * Exit - None + * + */ + +VOID demTerminatePDB (VOID) +{ + PPSP_FFINDLIST pPspFFindEntry; + USHORT PSP; + + PSP = getBX (); + + if(!IsFirstCall) + VDDTerminateUserHook(PSP); + /* let host knows a process is terminating */ + + HostTerminatePDB(PSP); + + pPspFFindEntry = GetPspFFindList(PSP); + if (!pPspFFindEntry) + return; + + if (!IsListEmpty(&pPspFFindEntry->FFindHeadList)) { + FreeFFindList( &pPspFFindEntry->FFindHeadList); + } + + RemoveEntryList(&pPspFFindEntry->PspFFindEntry); + free(pPspFFindEntry); + + return; +} + + +/* SearchFile - Common routine for FIND_FRST and FIND_NEXT + * + * Entry - + * PCHAR pwcFile file name to search for + * USHORT SearchAttr file attributes to match + * PFFINDLIST pFFindEntry, current list entry + * if new search FFindId is expected to be zero + * PFFINDDOSDATA pFFindDDOut, filled with the next file in search + * + * Exit - if no more files pFFindDDOut is filled with zeros + * returns PFFINDLIST if buffered entries exist, else NULL + */ +PFFINDLIST +SearchFile( + PWCHAR pwcFile, + USHORT SearchAttr, + PFFINDLIST pFFindEntry, + PFFINDDOSDATA pFFindDDOut) +{ + NTSTATUS Status; + ULONG BufferSize; + FFINDLIST FFindEntry; + PFFINDLIST pFFEntry = NULL; + + + SearchAttr &= ~(ATTR_READ_ONLY | ATTR_ARCHIVE | ATTR_DEVICE); + Status = STATUS_NO_MORE_FILES; + + if (pFFindDDOut) { + memset(pFFindDDOut, 0, sizeof(FFINDDOSDATA)); + } + + try { + if (pFFindEntry) { + pFFEntry = pFFindEntry; + Status = pFFindEntry->LastQueryStatus; + + if (pFFindDDOut) { + *pFFindDDOut = pFFEntry->DosData; + pFFEntry->DosData.cFileName[0] = '\0'; + } + else { + return pFFEntry; + } + + if (pFFEntry->FindBufferNext || pFFEntry->DirectoryHandle) { + NTSTATUS st; + + st = FileFindNext(&pFFEntry->DosData, + pFFEntry + ); + + if (NT_SUCCESS(st)) { + return pFFEntry; + } + + if (pFFEntry->DirectoryHandle) { + Status = st; + } + } + + // + // Check Last Known Status before retrying + // + if (!NT_SUCCESS(Status)) { + return NULL; + } + + + // + // Reopen the FileFind Handle with a large buffer size + // + Status = FileFindOpen(NULL, + pFFEntry, + 4096 + ); + if (!NT_SUCCESS(Status)) { + return NULL; + } + + // + // reset the search to the last known search pos + // + Status = FileFindReset(pFFEntry); + if (!NT_SUCCESS(Status)) { + return NULL; + } + } + else { + pFFEntry = &FFindEntry; + memset(pFFEntry, 0, sizeof(FFINDLIST)); + pFFEntry->SupportReset = TRUE; + pFFEntry->usSrchAttr = SearchAttr; + + + Status = FileFindOpen(pwcFile, + pFFEntry, + 1024 + ); + + if (!NT_SUCCESS(Status)) { + return NULL; + } + + // + // Fill up pFFindDDOut + // + if (pFFindDDOut) { + Status = FileFindNext(pFFindDDOut, pFFEntry); + if (!NT_SUCCESS(Status)) { + return NULL; + } + } + } + + // + // Fill up pFFEntry->DosData + // + Status = FileFindNext(&pFFEntry->DosData, pFFEntry); + if (!NT_SUCCESS(Status)) { + return NULL; + } + + + // + // if findfirst, fill in the static entries, and add the find entry + // + if (!pFFindEntry) { + pFFEntry->FFindId = NextFFindId++; + if (NextFFindId == 0xffffffff) { + NextFFindId = FFINDID_BASE; + FFindIdWrap = TRUE; + } + + if (FFindIdWrap) { + pFFindEntry = GetFFindEntryByFindId(NextFFindId); + if (pFFindEntry) { + FreeFFindEntry(pFFindEntry); + pFFindEntry = NULL; + } + } + + pFFEntry = AddFFindEntry(pwcFile, pFFEntry); + if (!pFFEntry) { + pFFEntry = &FFindEntry; + pFFEntry->DosData.cFileName[0] = '\0'; + Status = STATUS_NO_MEMORY; + return NULL; + } + } + + + // + // Try to fill one more entry. If the NtQuery for this search + // is complete we can set the LastQueryStatus, and close dir handles. + // + Status = FileFindLast(pFFEntry); + + + } + finally { + + if (pFFEntry) { + + pFFEntry->LastQueryStatus = Status; + + // + // if nothing is buffered, cleanup look aheads + // + if (!pFFEntry->DosData.cFileName[0] || + pFFEntry->DirectoryHandle == FINDFILE_DEVICE) + { + if (pFFEntry == &FFindEntry) { + FileFindClose(pFFEntry); + RtlFreeUnicodeString(&pFFEntry->FileName); + RtlFreeUnicodeString(&pFFEntry->PathName); + } + else { + FreeFFindEntry(pFFEntry); + } + SetLastError(RtlNtStatusToDosError(Status)); + pFFEntry = NULL; + } + } + + + + if (pFFEntry) { + + if (pFFEntry->DirectoryHandle) { + if (!pFFindEntry || !NT_SUCCESS(pFFEntry->LastQueryStatus)) { + NumDirectoryHandle--; + NtClose(pFFEntry->DirectoryHandle); + pFFEntry->DirectoryHandle = 0; + } + } + + if (NumFindBuffer > MAX_FINDBUFFER || + NumDirectoryHandle > MAX_DIRECTORYHANDLE) + { + CloseOldestFileFindBuffer(); + } + + // + // Set HeartBeat timer to close find buffers, directory handle + // Tics = 8(min) * 60(sec/min) * 18(tic/sec) + // + pFFEntry->FindFileTics.QuadPart = 8640 + FindFileTics.QuadPart; + if (!FindFileTics.QuadPart) { + NextFindFileTics.QuadPart = pFFEntry->FindFileTics.QuadPart; + } + } + + + } + + return pFFEntry; +} + + + +NTSTATUS +FileFindOpen( + PWCHAR pwcFile, + PFFINDLIST pFFindEntry, + ULONG BufferSize + ) +{ + NTSTATUS Status; + BOOLEAN bStatus; + BOOLEAN bReturnSingleEntry; + PWCHAR pwc; + OBJECT_ATTRIBUTES Obja; + PUNICODE_STRING FileName; + PUNICODE_STRING PathName; + IO_STATUS_BLOCK IoStatusBlock; + PFILE_BOTH_DIR_INFORMATION DirectoryInfo; + + + Status = STATUS_SUCCESS; + PathName = &pFFindEntry->PathName; + FileName = &pFFindEntry->FileName; + + try { + + if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) { + Status = STATUS_NO_MORE_FILES; + goto FFOFinallyExit; + } + + + if (BufferSize <= sizeof(FILE_BOTH_DIR_INFORMATION) + + MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)) + { + Status = STATUS_BUFFER_TOO_SMALL; + goto FFOFinallyExit; + } + + + + if (pwcFile) { + bStatus = RtlDosPathNameToNtPathName_U(pwcFile, + PathName, + &pwc, + NULL + ); + + if (!bStatus ) { + Status = STATUS_OBJECT_PATH_NOT_FOUND; + goto FFOFinallyExit; + } + + // + // Copy out the PathName, FileName + // + if (pwc) { + bStatus = RtlCreateUnicodeString(FileName, + pwc + ); + if (!bStatus) { + Status = STATUS_NO_MEMORY; + goto FFOFinallyExit; + } + + PathName->Length = (USHORT)((ULONG)pwc - (ULONG)PathName->Buffer); + if (PathName->Buffer[(PathName->Length>>1)-2] != (WCHAR)':' ) { + PathName->Length -= sizeof(UNICODE_NULL); + } + } + else { + FileName->Length = 0; + FileName->MaximumLength = 0; + } + + bReturnSingleEntry = FALSE; + } + else { + bReturnSingleEntry = pFFindEntry->SupportReset; + } + + + + // + // Prepare Find Buffer for NtQueryDirectory + // + if (BufferSize != pFFindEntry->FindBufferLength) { + if (pFFindEntry->FindBufferBase) { + RtlFreeHeap(RtlProcessHeap(), 0, pFFindEntry->FindBufferBase); + } + else { + NumFindBuffer++; + } + + pFFindEntry->FindBufferBase = RtlAllocateHeap(RtlProcessHeap(), + 0, + BufferSize + ); + if (!pFFindEntry->FindBufferBase) { + Status = STATUS_NO_MEMORY; + goto FFOFinallyExit; + } + } + + pFFindEntry->FindBufferNext = NULL; + pFFindEntry->FindBufferLength = BufferSize; + DirectoryInfo = pFFindEntry->FindBufferBase; + + // + // Open the directory for list access + // + if (!pFFindEntry->DirectoryHandle) { + + InitializeObjectAttributes( + &Obja, + PathName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenFile( + &pFFindEntry->DirectoryHandle, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + &Obja, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT + ); + + if (!NT_SUCCESS(Status)) { + + if (pwcFile) { + pFFindEntry->DirectoryHandle = FileFindFirstDevice(pwcFile, + DirectoryInfo + ); + } + else { + pFFindEntry->DirectoryHandle = NULL; + } + + if (pFFindEntry->DirectoryHandle) { + Status = STATUS_SUCCESS; + goto FFOFinallyExit; + } + + if (Status == STATUS_OBJECT_NAME_NOT_FOUND || + Status == STATUS_OBJECT_TYPE_MISMATCH ) + { + Status = STATUS_OBJECT_PATH_NOT_FOUND; + } + goto FFOFinallyExit; + } + + NumDirectoryHandle++; + } + + + // + // Prepare the filename for NtQueryDirectory + // + + if (pwcFile) { + WCHAR wchCurr, wchPrev; + + int Len = FileName->Length/sizeof(WCHAR); + + // + // If there is no file part, but we are not looking at a device exit + // + if (!Len) { + Status = STATUS_OBJECT_PATH_NOT_FOUND; + goto FFOFinallyExit; + } + + + // + // ntio expects the following transmogrifications: + // + // - Change all ? to DOS_QM + // - Change all . followed by ? or * to DOS_DOT + // - Change all * followed by a . into DOS_STAR + // + // However, the doskrnl and wow32 have expanded '*'s to '?'s + // so the * rules can be ignored. + // + pwc = FileName->Buffer; + wchPrev = 0; + while (Len--) { + wchCurr = *pwc; + + if (wchCurr == L'?') { + if (wchPrev == L'.') { + *(pwc - 1) = DOS_DOT; + } + + *pwc = DOS_QM; + } + + wchPrev = wchCurr; + pwc++; + } + + } + +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, + "FFOpen %x %ws (%ws)\n", + pFFindEntry->DirectoryHandle, + FileName->Buffer, + pwcFile + ); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + + // + // Do an initial query to fill the buffers, and verify everything is ok + // + + Status = NtQueryDirectoryFile( + pFFindEntry->DirectoryHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + DirectoryInfo, + BufferSize, + FileBothDirectoryInformation, + bReturnSingleEntry, + FileName, + FALSE + ); + +FFOFinallyExit:; + + } + finally { + if (!NT_SUCCESS(Status)) { +#if DBG + if ((fShowSVCMsg & DEMFILIO) && !NT_SUCCESS(Status)) { + sprintf(demDebugBuffer, "FFOpen Status %x\n", Status); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + FileFindClose(pFFindEntry); + RtlFreeUnicodeString(PathName); + PathName->Buffer = NULL; + RtlFreeUnicodeString(FileName); + FileName->Buffer = NULL; + } + else { + pFFindEntry->FindBufferNext = pFFindEntry->FindBufferBase; + } + } + + return Status; +} + + + +/* + * Closes a FileFindHandle + */ +VOID +FileFindClose( + PFFINDLIST pFFindEntry + ) +{ + NTSTATUS Status; + HANDLE DirectoryHandle; + + DirectoryHandle = pFFindEntry->DirectoryHandle; + if (DirectoryHandle && + DirectoryHandle != FINDFILE_DEVICE) + { + NtClose(DirectoryHandle); + --NumDirectoryHandle; + } + + pFFindEntry->DirectoryHandle = 0; + + if (pFFindEntry->FindBufferBase) { + RtlFreeHeap(RtlProcessHeap(), 0, pFFindEntry->FindBufferBase); + --NumFindBuffer; + } + + pFFindEntry->FindBufferBase = NULL; + pFFindEntry->FindBufferNext = NULL; + pFFindEntry->FindBufferLength = 0; + pFFindEntry->FindFileTics.QuadPart = 0; + + if (!NumDirectoryHandle && !NumFindBuffer) { + FindFileTics.QuadPart = 0; + NextFindFileTics.QuadPart = 0; + } +} + + + +/* + * FileFindReset + * + * Resets search pos according to FileName, FileIndex. + * The FindBuffers will point to the next file in the search + * order. Assumes that the remembered search pos, has not been + * reached yet for the current search. + * + */ +NTSTATUS +FileFindReset( + PFFINDLIST pFFindEntry + ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + PFILE_BOTH_DIR_INFORMATION DirectoryInfo; + UNICODE_STRING LastFileName; + UNICODE_STRING CurrFileName; + BOOLEAN bSlowReset; + + + if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) { + return STATUS_NO_MORE_FILES; + } + + Status = STATUS_UNSUCCESSFUL; + + LastFileName.Length = (USHORT)pFFindEntry->DosData.FileNameLength; + LastFileName.MaximumLength = (USHORT)pFFindEntry->DosData.FileNameLength; + LastFileName.Buffer = pFFindEntry->DosData.FileName; + + RtlInitUnicodeString(&CurrFileName, L"."); + if (!RtlCompareUnicodeString(&LastFileName, &CurrFileName, TRUE)) { + bSlowReset = TRUE; + } + else { + RtlInitUnicodeString(&CurrFileName, L".."); + if (!RtlCompareUnicodeString(&LastFileName, &CurrFileName, TRUE)) { + bSlowReset = TRUE; + } + else { + bSlowReset = FALSE; + } + } + + // + // if the last file name, wasn't Dots and the volume supports reset + // functionality call nt file sysetm to do the reset. + // + if (!bSlowReset && pFFindEntry->SupportReset) { + VDMQUERYDIRINFO VdmQueryDirInfo; + UNICODE_STRING UnicodeString; + + DirectoryInfo = (PFILE_BOTH_DIR_INFORMATION) pFFindEntry->FindBufferBase; + + VdmQueryDirInfo.FileHandle = pFFindEntry->DirectoryHandle; + VdmQueryDirInfo.FileInformation = DirectoryInfo; + VdmQueryDirInfo.Length = pFFindEntry->FindBufferLength; + VdmQueryDirInfo.FileIndex = pFFindEntry->DosData.FileIndex; + + UnicodeString.Length = (USHORT)pFFindEntry->DosData.FileNameLength; + UnicodeString.MaximumLength = UnicodeString.Length; + UnicodeString.Buffer = pFFindEntry->DosData.FileName; + VdmQueryDirInfo.FileName = &UnicodeString; + + Status = NtVdmControl(VdmQueryDir, &VdmQueryDirInfo); + if (NT_SUCCESS(Status) || + Status == STATUS_NO_MORE_FILES || Status == STATUS_NO_SUCH_FILE) + { + return Status; + } + + pFFindEntry->SupportReset = TRUE; + + } + + // + // Reset the slow way by comparing FileName directly. + // + // WARNING: if the "remembered" File has been deleted we will + // fail, is there something else we can do ? + // + + Status = STATUS_NO_MORE_FILES; + while (TRUE) { + + // + // If there is no data in the find file buffer, call NtQueryDir + // + + DirectoryInfo = pFFindEntry->FindBufferNext; + if (!DirectoryInfo) { + DirectoryInfo = pFFindEntry->FindBufferBase; + + Status = NtQueryDirectoryFile( + pFFindEntry->DirectoryHandle, + NULL, // no event + NULL, // no apcRoutine + NULL, // no apcContext + &IoStatusBlock, + DirectoryInfo, + pFFindEntry->FindBufferLength, + FileBothDirectoryInformation, + FALSE, // single entry + NULL, // no file name + FALSE + ); + + if (!NT_SUCCESS(Status)) { +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "FFReset Status %x\n", Status); + OutputDebugStringOem(demDebugBuffer); + } +#endif + return Status; + } + } + + if ( DirectoryInfo->NextEntryOffset ) { + pFFindEntry->FindBufferNext = (PVOID)((ULONG)DirectoryInfo + + DirectoryInfo->NextEntryOffset); + } + else { + pFFindEntry->FindBufferNext = NULL; + } + + + if (DirectoryInfo->FileIndex == pFFindEntry->DosData.FileIndex) { + CurrFileName.Length = (USHORT)DirectoryInfo->FileNameLength; + CurrFileName.MaximumLength = (USHORT)DirectoryInfo->FileNameLength; + CurrFileName.Buffer = DirectoryInfo->FileName; + + if (!RtlCompareUnicodeString(&LastFileName, &CurrFileName, TRUE)) { + return STATUS_SUCCESS; + } + } + + } + + return Status; + +} + + + + +/* + * FileFindLast - Attempts to fill the FindFile buffer completely. + * + * + * PFFINDLIST pFFindEntry - + * + * Returns - Status of NtQueryDir operation if invoked, otherwise + * STATUS_SUCCESS. + * + */ +NTSTATUS +FileFindLast( + PFFINDLIST pFFindEntry + ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + PFILE_BOTH_DIR_INFORMATION DirInfo, LastDirInfo; + LONG BytesLeft; + + if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) { + return STATUS_NO_MORE_FILES; + } + + if (pFFindEntry->FindBufferNext) { + ULONG BytesOffset; + + BytesOffset = (ULONG)pFFindEntry->FindBufferNext - + (ULONG)pFFindEntry->FindBufferBase; + + if (BytesOffset) { + RtlMoveMemory(pFFindEntry->FindBufferBase, + pFFindEntry->FindBufferNext, + pFFindEntry->FindBufferLength - BytesOffset + ); + } + + pFFindEntry->FindBufferNext = pFFindEntry->FindBufferBase; + DirInfo = pFFindEntry->FindBufferBase; + + while (DirInfo->NextEntryOffset) { + DirInfo = (PVOID)((ULONG)DirInfo + DirInfo->NextEntryOffset); + } + LastDirInfo = DirInfo; + + DirInfo = (PVOID)&DirInfo->FileName[DirInfo->FileNameLength>>1]; + + DirInfo = (PVOID) (((ULONG) DirInfo + sizeof(LONGLONG) - 1) & + ~(sizeof(LONGLONG) - 1)); + + BytesLeft = pFFindEntry->FindBufferLength - + ((ULONG)DirInfo - (ULONG)pFFindEntry->FindBufferBase); + } + else { + DirInfo = pFFindEntry->FindBufferBase; + LastDirInfo = NULL; + BytesLeft = pFFindEntry->FindBufferLength; + } + + + // the size of the dirinfo structure including the name must be a longlong. + while (BytesLeft > sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(LONGLONG)) { + + Status = NtQueryDirectoryFile( + pFFindEntry->DirectoryHandle, + NULL, // no event + NULL, // no apcRoutine + NULL, // no apcContext + &IoStatusBlock, + DirInfo, + BytesLeft, + FileBothDirectoryInformation, + FALSE, // single entry ? + NULL, // no file name + FALSE + ); + + if (Status == STATUS_NO_MORE_FILES || Status == STATUS_NO_SUCH_FILE) { +#if DBG + if ((fShowSVCMsg & DEMFILIO)) { + sprintf(demDebugBuffer, "FFLast Status %x\n", Status); + OutputDebugStringOem(demDebugBuffer); + } +#endif + return Status; + } + + + if (!NT_SUCCESS(Status)) { + break; + } + + if (LastDirInfo) { + LastDirInfo->NextEntryOffset =(ULONG)DirInfo - (ULONG)LastDirInfo; + } + else { + pFFindEntry->FindBufferNext = pFFindEntry->FindBufferBase; + } + + while (DirInfo->NextEntryOffset) { + DirInfo = (PVOID)((ULONG)DirInfo + DirInfo->NextEntryOffset); + } + LastDirInfo = DirInfo; + DirInfo = (PVOID)&DirInfo->FileName[DirInfo->FileNameLength>>1]; + + DirInfo = (PVOID) (((ULONG) DirInfo + sizeof(LONGLONG) - 1) & + ~(sizeof(LONGLONG) - 1)); + + BytesLeft = pFFindEntry->FindBufferLength - + ((ULONG)DirInfo - (ULONG)pFFindEntry->FindBufferBase); + } + + return STATUS_SUCCESS; +} + + + + + + +/* + * FileFindNext - retrieves the next file in the current search order, + * + * PFFINDDOSDATA pFFindDD + * Receives File info returned by the nt FileSystem + * + * PFFINDLIST pFFindEntry - + * Contains the DirectoryInfo (FileName,FileIndex) necessary to reset a + * search pos. For operations other than QDIR_RESET_SCAN, this is ignored. + * + * Returns - + * If Got a DirectoryInformation Entry, STATUS_SUCCESS + * If no Open Directory handle and is unknown if there are more files + * returns STATUS_IN`VALID_HANDLE + * + */ +NTSTATUS +FileFindNext( + PFFINDDOSDATA pFFindDD, + PFFINDLIST pFFindEntry + ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + + PFILE_BOTH_DIR_INFORMATION DirectoryInfo; + + if (pFFindEntry->DirectoryHandle == FINDFILE_DEVICE) { + return STATUS_NO_MORE_FILES; + } + + Status = STATUS_UNSUCCESSFUL; + + do { + + // + // If there is no data in the find file buffer, call NtQueryDir + // + + DirectoryInfo = pFFindEntry->FindBufferNext; + if (!DirectoryInfo) { + if (!pFFindEntry->DirectoryHandle) { + return STATUS_INVALID_HANDLE; + } + + DirectoryInfo = pFFindEntry->FindBufferBase; + + Status = NtQueryDirectoryFile( + pFFindEntry->DirectoryHandle, + NULL, // no event + NULL, // no apcRoutine + NULL, // no apcContext + &IoStatusBlock, + DirectoryInfo, + pFFindEntry->FindBufferLength, + FileBothDirectoryInformation, + FALSE, // single entry ? + NULL, // no file name + FALSE + ); + + if (!NT_SUCCESS(Status)) { +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "FFNext Status %x\n", Status); + OutputDebugStringOem(demDebugBuffer); + } +#endif + return Status; + } + } + + + if ( DirectoryInfo->NextEntryOffset ) { + pFFindEntry->FindBufferNext = (PVOID)((ULONG)DirectoryInfo + + DirectoryInfo->NextEntryOffset); + } + else { + pFFindEntry->FindBufferNext = NULL; + } + + } while (!CopyDirInfoToDosData(pFFindDD, + DirectoryInfo, + pFFindEntry->usSrchAttr + )); + + return STATUS_SUCCESS; +} + + + + +/* + * CopyDirInfoToDosData + * + */ +BOOL +CopyDirInfoToDosData( + PFFINDDOSDATA pFFindDD, + PFILE_BOTH_DIR_INFORMATION DirInfo, + USHORT SearchAttr + ) +{ + NTSTATUS Status; + OEM_STRING OemString; + UNICODE_STRING UnicodeString; + DWORD dwAttr; + BOOLEAN SpacesInName = FALSE; + BOOLEAN NameValid8Dot3; + + // + // match the attributes + // See DOS5.0 sources (dir2.asm, MatchAttributes) + // ignores READONLY and ARCHIVE bits + // + if (FILE_ATTRIBUTE_NORMAL == DirInfo->FileAttributes) { + DirInfo->FileAttributes = 0; + } + else { + DirInfo->FileAttributes &= DOS_ATTR_MASK; + } + + + dwAttr = DirInfo->FileAttributes; + dwAttr &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY); + if (((~(ULONG)SearchAttr) & dwAttr) & ATTR_ALL) + return FALSE; + + + // + // set up the destination oem string buffer + // + OemString.Buffer = pFFindDD->cFileName; + OemString.MaximumLength = 14; + + // + // see if the name is legal fat + // + + UnicodeString.Buffer = DirInfo->FileName; + UnicodeString.Length = (USHORT)DirInfo->FileNameLength; + UnicodeString.MaximumLength = (USHORT)DirInfo->FileNameLength; + + NameValid8Dot3 = RtlIsNameLegalDOS8Dot3( &UnicodeString, + &OemString, + &SpacesInName ); + + // + // if failed (incompatible codepage or illegal FAT name), + // use the short name + // + if (!NameValid8Dot3 || + (SpacesInName && (DirInfo->ShortName[0] != UNICODE_NULL))) { + + if (DirInfo->ShortName[0] == UNICODE_NULL) { + pFFindDD->cFileName[0] = '\0'; + return FALSE; + } + + UnicodeString.Buffer = DirInfo->ShortName; + UnicodeString.Length = (USHORT)DirInfo->ShortNameLength; + UnicodeString.MaximumLength = (USHORT)DirInfo->ShortNameLength; + + if (!NT_SUCCESS(RtlUpcaseUnicodeStringToCountedOemString(&OemString, &UnicodeString, FALSE))) { + pFFindDD->cFileName[0] = '\0'; + return FALSE; + } + } + + OemString.Buffer[OemString.Length] = '\0'; + + // fill in time, size and attributes + pFFindDD->ftLastWriteTime = *(LPFILETIME)&DirInfo->LastWriteTime; + pFFindDD->dwFileSizeLow = DirInfo->EndOfFile.LowPart; + pFFindDD->uchFileAttributes = (UCHAR)DirInfo->FileAttributes; + + // Save File Name, Index for restarting searches + pFFindDD->FileIndex = DirInfo->FileIndex; + pFFindDD->FileNameLength = DirInfo->FileNameLength; + + RtlCopyMemory(pFFindDD->FileName, + DirInfo->FileName, + DirInfo->FileNameLength + ); + + pFFindDD->FileName[DirInfo->FileNameLength >> 1] = UNICODE_NULL; + + return TRUE; +} + + + + +HANDLE +FileFindFirstDevice( + PWCHAR FileName, + PFILE_BOTH_DIR_INFORMATION DirectoryInfo + ) + +/*++ + +Routine Description: + + Determines if the FileName is a device, and copies out the + device name found if it is. + +Arguments: + + FileName - Supplies the device name of the file to find. + + pQueryDirInfo - On a successful find, this parameter returns information + about the located file. + +Return Value: + + +--*/ + +{ + ULONG DeviceNameData; + PWSTR DeviceName; + + DeviceNameData = RtlIsDosDeviceName_U(FileName); + if (DeviceNameData) { + RtlZeroMemory(DirectoryInfo, sizeof(FILE_BOTH_DIR_INFORMATION)); + + DirectoryInfo->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; + DeviceName = (PWSTR)((ULONG)FileName + (DeviceNameData >> 16)); + + DeviceNameData &= 0xffff; + + DirectoryInfo->FileNameLength = DeviceNameData; + DirectoryInfo->ShortNameLength = (CCHAR)DeviceNameData; + + + RtlCopyMemory(DirectoryInfo->FileName, + DeviceName, + DeviceNameData + ); + + RtlCopyMemory(DirectoryInfo->ShortName, + DeviceName, + DeviceNameData + ); + + return FINDFILE_DEVICE; + } + + return NULL; +} + + + + +/* FillFcbVolume - fill Volume info in the FCB + * + * Entry - pSrchBuf FCB Search buffer to be filled in + * FileName File Name (interesting part is the drive letter) + * + * Exit - SUCCESS + * Client (CF) - 0 + * pSrchBuf is filled with volume info + * + * FAILURE + * Client (CF) - 1 + * Client (AX) = Error Code + */ +VOID +FillFcbVolume( + PSRCHBUF pSrchBuf, + CHAR *pFileName, + USHORT SearchAttr + ) +{ + CHAR *pch; + PDIRENT pDirEnt = &pSrchBuf->DirEnt; + CHAR FullPathBuffer[MAX_PATH]; + CHAR achBaseName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.', and null + CHAR achVolumeName[NT_VOLUME_NAME_SIZE]; + + // + // form a path without base name + // this makes sure only on root directory will get the + // volume label(the GetVolumeInformationOem will fail + // if the given path is not root directory) + // + + strcpy(FullPathBuffer, pFileName); + pch = strrchr(FullPathBuffer, '\\'); + if (pch) { + pch++; + // truncate to dos file name length (including period) + pch[DOS_VOLUME_NAME_SIZE + 1] = '\0'; + strcpy(achBaseName, pch); + _strupr(achBaseName); + *pch = '\0'; + } + else { + achBaseName[0] = '\0'; + } + + + // + // if searching for volume only the DOS uses first 3 letters for + // root drive path ignoring the rest of the path + // as long as the full pathname is valid. + // + if (SearchAttr == ATTR_VOLUME_ID && + (pch = strchr(FullPathBuffer, '\\')) && + GetFileAttributes(FullPathBuffer) != 0xffffffff ) + { + pch++; + *pch = '\0'; + strcpy(achBaseName, szStartDotStar); + } + + + if (GetVolumeInformationOem(FullPathBuffer, + achVolumeName, + NT_VOLUME_NAME_SIZE, + NULL, + NULL, + NULL, + NULL, + 0) == FALSE) + { + + demClientError(INVALID_HANDLE_VALUE, *pFileName); + return; + } + + // truncate to dos volumen max size (no period) + achVolumeName[DOS_VOLUME_NAME_SIZE] = '\0'; + + if (!achVolumeName[0] || !MatchVolLabel(achVolumeName, achBaseName)) { + SetLastError(ERROR_NO_MORE_FILES); + demClientError(INVALID_HANDLE_VALUE, *pFileName); + return; + } + + // warning !!! this assumes the FileExt follows FileName immediately + memset(pSrchBuf->FileName, ' ', DOS_VOLUME_NAME_SIZE); + strncpy(pSrchBuf->FileName, achVolumeName, strlen(achVolumeName)); + + // Now copy the directory entry + strncpy(pDirEnt->FileName,pSrchBuf->FileName,8); + strncpy(pDirEnt->FileExt,pSrchBuf->FileExt,3); + setCF (0); + return; +} + + +/* FillDtaVolume - fill Volume info in the DTA + * + * Entry - CHAR lpSearchName - Optional name to match with volume name + * + * + * Exit - SUCCESS + * Returns - 0 + * pSrchBuf is filled with volume info + * + * FAILURE + * Returns Error Code + */ + +BOOL FillDtaVolume( + CHAR *pFileName, + PSRCHDTA pDta, + USHORT SearchAttr + ) +{ + CHAR *pch; + CHAR FullPathBuffer[MAX_PATH]; + CHAR achBaseName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.' and null + CHAR achVolumeName[NT_VOLUME_NAME_SIZE]; + + // + // form a path without base name + // this makes sure only on root directory will get the + // volume label(the GetVolumeInformationOem will fail + // if the given path is not root directory) + // + strcpy(FullPathBuffer, pFileName); + pch = strrchr(FullPathBuffer, '\\'); + if (pch) { + pch++; + pch[DOS_VOLUME_NAME_SIZE + 1] = '\0'; // max len (including period) + strcpy(achBaseName, pch); + _strupr(achBaseName); + *pch = '\0'; + } + else { + achBaseName[0] = '\0'; + } + + + // + // if searching for volume only the DOS uses first 3 letters for + // root drive path ignoring the rest of the path + // as long as the full path name is valid. + // + if (SearchAttr == ATTR_VOLUME_ID && + (pch = strchr(FullPathBuffer, '\\')) && + GetFileAttributes(FullPathBuffer) != 0xffffffff ) + { + pch++; + *pch = '\0'; + strcpy(achBaseName, szStartDotStar); + } + + if (GetVolumeInformationOem(FullPathBuffer, + achVolumeName, + NT_VOLUME_NAME_SIZE, + NULL, + NULL, + NULL, + NULL, + 0) == FALSE) + { + return FALSE; + } + + // truncate to dos file name length (no period) + achVolumeName[DOS_VOLUME_NAME_SIZE] = '\0'; + + if (!achVolumeName[0] || !MatchVolLabel(achVolumeName, achBaseName)) { + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; + } + + // + // DOS Dta search returns volume label in 8.3 format. But if label is + // more than 8 characters long than NT just returns that as it is + // without adding a ".". So here we have to add a "." in volume + // labels, if needed. But note that FCB based volume search does'nt + // add the "." So nothing need to be done there. + // + NtVolumeNameToDosVolumeName(pDta->achFileName, achVolumeName); + pDta->uchFileAttr = ATTR_VOLUME_ID; + STOREWORD(pDta->usLowSize,0); + STOREWORD(pDta->usHighSize,0); + + // Zero out dates as we can not fetch dates for volume labels. + STOREWORD(pDta->usTimeLastWrite,0); + STOREWORD(pDta->usDateLastWrite,0); + + return TRUE; +} + + + +/* + * MatchVolLabel + * Does a string compare to see if the vol label matches + * a FAT search string. The search string is expected to + * have the '*' character already expanded into '?' characters. + * + * WARNING: maintanes dos5.0 quirk of not caring about characters past + * the defined len of each part of the vol label. + * 12345678.123 + * ^ ^ + * + * foovol foovol1 (srch string) + * foo.vol foo.vol1 (srch string) + * + * entry: CHAR *pVol -- NT volume name + * CHAR *pSrch -- dos volume name + * + * exit: TRUE for a match + */ +BOOL MatchVolLabel(CHAR *pVol, CHAR *pSrch ) +{ + WORD w; + CHAR achDosVolumeName[DOS_VOLUME_NAME_SIZE + 2]; // 11 chars, '.' and null + + NtVolumeNameToDosVolumeName(achDosVolumeName, pVol); + pVol = achDosVolumeName; + + w = 8; + while (w--) { + if (*pVol == *pSrch) { + if (!*pVol && !*pSrch) + return TRUE; + } + else if (*pSrch == '.') { + if (*pVol) + return FALSE; + } + else if (*pSrch != '?') { + return FALSE; + } + + // move on to the next character + // but not past second component part + if (*pVol && *pVol != '.') + pVol++; + if (*pSrch && *pSrch != '.') + pSrch++; + } + + // skip trailing part of search string, in the first comp + while (*pSrch && *pSrch != '.') + pSrch++; + + + w = 4; + while (w--) { + if (*pVol == *pSrch) { + if (!*pVol && !*pSrch) + return TRUE; + } + else if (*pSrch == '.') { + if (*pVol) + return FALSE; + } + else if (*pSrch != '?') { + return FALSE; + } + + // move on to the next character + if (*pVol) + pVol++; + if (*pSrch) + pSrch++; + } + + return TRUE; +} + + +VOID NtVolumeNameToDosVolumeName(CHAR * pDosName, CHAR * pNtName) +{ + + char NtNameBuffer[NT_VOLUME_NAME_SIZE]; + int i; + char char8, char9, char10; + + // make a local copy so that the caller can use the same + // buffer + strcpy(NtNameBuffer, pNtName); + + if (strlen(NtNameBuffer) > 8) { + char8 = NtNameBuffer[8]; + char9 = NtNameBuffer[9]; + char10 = NtNameBuffer[10]; + // eat spaces from first 8 characters + i = 7; + while (NtNameBuffer[i] == ' ') + i--; + NtNameBuffer[i+1] = '.'; + NtNameBuffer[i+2] = char8; + NtNameBuffer[i+3] = char9; + NtNameBuffer[i+4] = char10; + NtNameBuffer[i+5] = '\0'; + } + strcpy(pDosName, NtNameBuffer); +} + + + + + +/* FillFCBSrchBuf - Fill the FCB Search buffer. + * + * Entry - pSrchBuf FCB Search buffer to be filled in + * hFind Search Handle + * fFirst TRUE if call from FindFirstFCB + * + * Exit - None (pSrchBuf filled in) + * + */ + +VOID FillFCBSrchBuf( + PFFINDDOSDATA pFFindDD, + PSRCHBUF pSrchBuf) +{ + PDIRENT pDirEnt = &pSrchBuf->DirEnt; + PCHAR pDot; + USHORT usDate,usTime,i; + FILETIME ftLocal; + +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "FillFCBSrchBuf<%s>\n", pFFindDD->cFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + // Copy file name (Max Name = 8 and Max ext = 3) + if ((pDot = strchr(pFFindDD->cFileName,'.')) == NULL) { + strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8); + _strnset(pSrchBuf->FileExt,'\x020',3); + } + else if (pDot == pFFindDD->cFileName) { + strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8); + _strnset(pSrchBuf->FileExt,'\x020',3); + } + else { + *pDot = '\0'; + strncpy(pSrchBuf->FileName,pFFindDD->cFileName,8); + *pDot++ = '\0'; + strncpy(pSrchBuf->FileExt,pDot,3); + } + + + for (i=0;i<8;i++) { + if (pSrchBuf->FileName[i] == '\0') + pSrchBuf->FileName[i]='\x020'; + } + + for (i=0;i<3;i++) { + if (pSrchBuf->FileExt[i] == '\0') + pSrchBuf->FileExt[i]='\x020'; + } + + STOREWORD(pSrchBuf->usCurBlkNumber,0); + STOREWORD(pSrchBuf->usRecordSize,0); + STOREDWORD(pSrchBuf->ulFileSize, pFFindDD->dwFileSizeLow); + + // Convert NT File time/date to DOS time/date + FileTimeToLocalFileTime (&pFFindDD->ftLastWriteTime,&ftLocal); + FileTimeToDosDateTime (&ftLocal, + &usDate, + &usTime); + + // Now copy the directory entry + strncpy(pDirEnt->FileName,pSrchBuf->FileName,8); + strncpy(pDirEnt->FileExt,pSrchBuf->FileExt,3); + + pDirEnt->uchAttributes = pFFindDD->uchFileAttributes; + + STOREWORD(pDirEnt->usTime,usTime); + STOREWORD(pDirEnt->usDate,usDate); + STOREDWORD(pDirEnt->ulFileSize,pFFindDD->dwFileSizeLow); + + return; +} + + + +/* FillSrchDta - Fill DTA for FIND_FIRST,FIND_NEXT operations. + * + * Entry - pW32FindData Buffer containing file data + * hFind - Handle returned by FindFirstFile + * PSRCHDTA pDta + * + * Exit - None + * + * Note : It is guranteed that file name adhers to 8:3 convention. + * demSrchFile makes sure of that condition. + * + */ +VOID +FillSrchDta( + PFFINDDOSDATA pFFindDD, + PSRCHDTA pDta) +{ + USHORT usDate,usTime; + FILETIME ftLocal; + + pDta->uchFileAttr = pFFindDD->uchFileAttributes; + + // Convert NT File time/date to DOS time/date + FileTimeToLocalFileTime (&pFFindDD->ftLastWriteTime,&ftLocal); + FileTimeToDosDateTime (&ftLocal, + &usDate, + &usTime); + + STOREWORD(pDta->usTimeLastWrite,usTime); + STOREWORD(pDta->usDateLastWrite,usDate); + STOREWORD(pDta->usLowSize,(USHORT)pFFindDD->dwFileSizeLow); + STOREWORD(pDta->usHighSize,(USHORT)(pFFindDD->dwFileSizeLow >> 16)); + +#if DBG + if (fShowSVCMsg & DEMFILIO) { + sprintf(demDebugBuffer, "FillSrchDta<%s>\n", pFFindDD->cFileName); + OutputDebugStringOem(demDebugBuffer); + } +#endif + + strncpy(pDta->achFileName,pFFindDD->cFileName, 13); + + return; +} + + + + + +VOID demCloseAllPSPRecords (VOID) +{ + PLIST_ENTRY Next; + PPSP_FFINDLIST pPspFFindEntry; + + Next = PspFFindHeadList.Flink; + while (Next != &PspFFindHeadList) { + pPspFFindEntry = CONTAINING_RECORD(Next,PSP_FFINDLIST,PspFFindEntry); + FreeFFindList( &pPspFFindEntry->FFindHeadList); + Next= Next->Flink; + RemoveEntryList(&pPspFFindEntry->PspFFindEntry); + free(pPspFFindEntry); + } +} + + +void +DemHeartBeat(void) +{ + + PLIST_ENTRY Next; + PLIST_ENTRY pFFindHeadList; + PPSP_FFINDLIST pPspFFindEntry; + PFFINDLIST pFFindEntry; + + if (!NumFindBuffer || + NextFindFileTics.QuadPart > ++FindFileTics.QuadPart) + { + return; + } + + pPspFFindEntry = GetPspFFindList(FETCHWORD(pusCurrentPDB[0])); + if (!pPspFFindEntry) { + return; + } + pFFindHeadList = &pPspFFindEntry->FFindHeadList; + Next = pFFindHeadList->Blink; + while (Next != pFFindHeadList) { + pFFindEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry); + + if (pFFindEntry->FindFileTics.QuadPart) { + if (pFFindEntry->FindFileTics.QuadPart <= FindFileTics.QuadPart) { + FileFindClose(pFFindEntry); + } + else { + NextFindFileTics.QuadPart = pFFindEntry->FindFileTics.QuadPart; + return; + } + } + + Next = Next->Blink; + } + + NextFindFileTics.QuadPart = 0; + FindFileTics.QuadPart = 0; +} + + + + + +// +// CloseOldestFileFindBuffer +// walks the psp file find list backwards to find the oldest +// entry with FindBuffers, directory handles and closes it. +// +void +CloseOldestFileFindBuffer( + void + ) +{ + PLIST_ENTRY Next, NextPsp; + PLIST_ENTRY pFFindHeadList; + PPSP_FFINDLIST pPspFFindEntry; + PFFINDLIST pFFEntry; + + NextPsp = PspFFindHeadList.Blink; + while (NextPsp != &PspFFindHeadList) { + pPspFFindEntry = CONTAINING_RECORD(NextPsp,PSP_FFINDLIST,PspFFindEntry); + + pFFindHeadList = &pPspFFindEntry->FFindHeadList; + Next = pFFindHeadList->Blink; + while (Next != pFFindHeadList) { + pFFEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry); + if (NumFindBuffer >= MAX_FINDBUFFER) { + FileFindClose(pFFEntry); + } + else if (pFFEntry->DirectoryHandle && + NumDirectoryHandle >= MAX_DIRECTORYHANDLE) + { + NumDirectoryHandle--; + NtClose(pFFEntry->DirectoryHandle); + pFFEntry->DirectoryHandle = 0; + } + + if (NumFindBuffer < MAX_FINDBUFFER && + NumDirectoryHandle < MAX_DIRECTORYHANDLE) + { + return; + } + Next = Next->Blink; + } + + NextPsp= NextPsp->Blink; + } +} + + + + + +/* + * GetFFindEntryByFindId + */ +PFFINDLIST GetFFindEntryByFindId(ULONG NextFFindId) +{ + PLIST_ENTRY NextPsp; + PLIST_ENTRY Next; + PPSP_FFINDLIST pPspFFindEntry; + PFFINDLIST pFFindEntry; + PLIST_ENTRY pFFindHeadList; + + NextPsp = PspFFindHeadList.Flink; + while (NextPsp != &PspFFindHeadList) { + pPspFFindEntry = CONTAINING_RECORD(NextPsp,PSP_FFINDLIST,PspFFindEntry); + + pFFindHeadList = &pPspFFindEntry->FFindHeadList; + Next = pFFindHeadList->Flink; + while (Next != pFFindHeadList) { + pFFindEntry = CONTAINING_RECORD(Next, FFINDLIST, FFindEntry); + if (pFFindEntry->FFindId == NextFFindId) { + return pFFindEntry; + } + Next= Next->Flink; + } + + NextPsp= NextPsp->Flink; + } + + return NULL; +} + + + +/* AddFFindEntry - Adds a new File Find entry to the current + * PSP's PspFileFindList + * + * Entry - + * + * Exit - PFFINDLIST pFFindList; + */ +PFFINDLIST +AddFFindEntry( + PWCHAR pwcFile, + PFFINDLIST pFFindEntrySrc + ) + +{ + PPSP_FFINDLIST pPspFFindEntry; + PFFINDLIST pFFindEntry; + ULONG Len; + + pPspFFindEntry = GetPspFFindList(FETCHWORD(pusCurrentPDB[0])); + + // + // if a Psp entry doesn't exist + // Allocate one, initialize it and insert it into the list + // + if (!pPspFFindEntry) { + pPspFFindEntry = (PPSP_FFINDLIST) malloc(sizeof(PSP_FFINDLIST)); + if (!pPspFFindEntry) + return NULL; + + pPspFFindEntry->usPsp = FETCHWORD(pusCurrentPDB[0]); + InitializeListHead(&pPspFFindEntry->FFindHeadList); + InsertHeadList(&PspFFindHeadList, &pPspFFindEntry->PspFFindEntry); + } + + // + // Create the FileFindEntry and add to the FileFind list + // + pFFindEntry = (PFFINDLIST) malloc(sizeof(FFINDLIST)); + if (!pFFindEntry) { + return pFFindEntry; + } + + // + // Fill in FFindList + // + *pFFindEntry = *pFFindEntrySrc; + + // + // Insert at the head of this psp list + // + InsertHeadList(&pPspFFindEntry->FFindHeadList, &pFFindEntry->FFindEntry); + + return pFFindEntry; +} + + + + + +/* FreeFFindEntry + * + * Entry - PFFINDLIST pFFindEntry + * + * Exit - None + * + */ +VOID FreeFFindEntry(PFFINDLIST pFFindEntry) +{ + RemoveEntryList(&pFFindEntry->FFindEntry); + FileFindClose(pFFindEntry); + RtlFreeUnicodeString(&pFFindEntry->FileName); + RtlFreeUnicodeString(&pFFindEntry->PathName); + free(pFFindEntry); + return; +} + + + +/* FreeFFindList + * + * Entry - Frees the entire list + * + * Exit - None + * + */ +VOID FreeFFindList(PLIST_ENTRY pFFindHeadList) +{ + PLIST_ENTRY Next; + PFFINDLIST pFFindEntry; + + Next = pFFindHeadList->Flink; + while (Next != pFFindHeadList) { + pFFindEntry = CONTAINING_RECORD(Next,FFINDLIST, FFindEntry); + Next= Next->Flink; + FreeFFindEntry(pFFindEntry); + } + + return; +} + + +/* GetPspFFindList + * + * Entry - USHORT CurrPsp + * + * Exit - Success - PPSP_FFINDLIST + * Failure - NULL + * + */ +PPSP_FFINDLIST GetPspFFindList(USHORT CurrPsp) +{ + PLIST_ENTRY Next; + PPSP_FFINDLIST pPspFFindEntry; + + Next = PspFFindHeadList.Flink; + while (Next != &PspFFindHeadList) { + pPspFFindEntry = CONTAINING_RECORD(Next,PSP_FFINDLIST,PspFFindEntry); + if (CurrPsp == pPspFFindEntry->usPsp) { + return pPspFFindEntry; + } + Next= Next->Flink; + } + + return NULL; +} diff --git a/private/mvdm/dos/dem/dosdef.h b/private/mvdm/dos/dem/dosdef.h new file mode 100644 index 000000000..4f9af4dcb --- /dev/null +++ b/private/mvdm/dos/dem/dosdef.h @@ -0,0 +1,140 @@ +/* dosdef.h - This file duplicates few important dos defines of use to + * DEM. + * + * As these defines are not going to change at all, its better to give + * DEM a separate copy and not share h and inc files between DOSKRNL and + * DEM. + * + * Sudeepb 05-Apr-1991 Created + */ + +#include <doswow.h> +#include <curdir.h> + +/** DEFINES **/ + +/** File Attributes **/ + +#define ATTR_NORMAL 0x0 +#define ATTR_READ_ONLY 0x1 +#define ATTR_HIDDEN 0x2 +#define ATTR_SYSTEM 0x4 +#define ATTR_VOLUME_ID 0x8 +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_DEVICE 0x40 + +#define ATTR_ALL (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY) +#define DOS_ATTR_MASK 0x0037 // ATTR_DEVICE isn't used on 32 bit side. + // ATTR_VOL maps to FILE_ATTRIBUTES_NORMAL. + +/** File Modes **/ + +#define ACCESS_MASK 0x0F +#define OPEN_FOR_READ 0x00 +#define OPEN_FOR_WRITE 0x01 +#define OPEN_FOR_BOTH 0x02 +#define EXEC_OPEN 0x03 /* access code of 3 indicates that + open was made from exec */ + +#define SHARING_MASK 0x70 +#define SHARING_COMPAT 0x00 +#define SHARING_DENY_BOTH 0x10 +#define SHARING_DENY_WRITE 0x20 +#define SHARING_DENY_READ 0x30 +#define SHARING_DENY_NONE 0x40 +#define SHARING_NET_FCB 0x70 +#define SHARING_NO_INHERIT 0x80 + + +/* Volume Info **/ + +#define DOS_VOLUME_NAME_SIZE 11 +#define NT_VOLUME_NAME_SIZE 255 +#define FILESYS_NAME_SIZE 8 + +/* IOCTLs **/ + +#define IOCTL_CHANGEABLE 8 +#define IOCTL_DeviceLocOrRem 9 +#define IOCTL_GET_DRIVE_MAP 0xE + +/** TYPEDEFS **/ + +/** SRCHDTA defines the DTA format for FIND_FIRST/NEXT operations **/ +#pragma pack(1) + +typedef struct _SRCHDTA { /* DTA */ + PVOID pFFindEntry; // 21 bytes reserved area begins + ULONG FFindId; + BYTE bReserved[13]; // 21 bytes reserved area ends + UCHAR uchFileAttr; + USHORT usTimeLastWrite; + USHORT usDateLastWrite; + USHORT usLowSize; + USHORT usHighSize; + CHAR achFileName[13]; +} SRCHDTA; + +#pragma pack() + +typedef SRCHDTA UNALIGNED *PSRCHDTA; + + +/** SRCHBUF - defines DOS SEARCHBUF data structure which is used in + * FCBFINDFIRST/NEXT operations. + */ + +#pragma pack(1) + +typedef struct _DIRENT { + CHAR FileName[8]; + CHAR FileExt[3]; + UCHAR uchAttributes; + PVOID pFFindEntry; // DOS Reserved Area + ULONG FFindId; // DOS Reserved Area + USHORT usDummy; // DOS Reserved Area + USHORT usTime; + USHORT usDate; + USHORT usReserved2; // Cluster Number in actual DOS + ULONG ulFileSize; +} DIRENT; + +#pragma pack() + +typedef DIRENT *PDIRENT; + +#pragma pack(1) + +typedef struct _SRCHBUF { + UCHAR uchDriveNumber; + CHAR FileName[8]; + CHAR FileExt[3]; + USHORT usCurBlkNumber; + USHORT usRecordSize; + ULONG ulFileSize; + DIRENT DirEnt; +} SRCHBUF; + +#pragma pack() + +typedef SRCHBUF *PSRCHBUF; + + +/** VOLINFO - GetSetMediaID data structure */ + +#pragma pack(1) + +typedef struct _VOLINFO { + USHORT usInfoLevel; + ULONG ulSerialNumber; + CHAR VolumeID[DOS_VOLUME_NAME_SIZE]; + CHAR FileSystemType[FILESYS_NAME_SIZE]; +} VOLINFO; + +#pragma pack() + +typedef VOLINFO *PVOLINFO; + + +/** CDS LIST - CurrDirStructure (Moved to DOSWOW.H) */ diff --git a/private/mvdm/dos/dem/makefile b/private/mvdm/dos/dem/makefile new file mode 100644 index 000000000..ab08ca0cf --- /dev/null +++ b/private/mvdm/dos/dem/makefile @@ -0,0 +1,9 @@ +# DEM makefile +# 01-Apr-1991 Sudeep Bharati Created +# + +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/mvdm/dos/dem/sources b/private/mvdm/dos/dem/sources new file mode 100644 index 000000000..2d9575fd4 --- /dev/null +++ b/private/mvdm/dos/dem/sources @@ -0,0 +1,65 @@ +!IF 0 + +Copyright (c) 1989-1991 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +History: + Created 27-Mar-1991 by Sudeep Bharati (sudeepb) + from template created 12-Apr-1990 by Steve Wood (stevewo) + + +NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=mvdm +MINORCOMP=dem + +TARGETNAME=dem +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=LIBRARY +TARGETLIBS= + + +NTPROFILEINPUT=YES + +SOFTPC_TREE=$(BASEDIR)\private\mvdm\softpc.new + +INCLUDES=..\..\inc;..\..\..\windows\inc;..\..\..\inc;$(SOFTPC_TREE)\base\inc;$(SOFTPC_TREE)\host\inc;..\..\vdd\h + +SOURCES=dem.c \ + demfcb.c \ + demdata.c \ + demdir.c \ + demdisp.c \ + demerror.c \ + demfile.c \ + demgset.c \ + demhndl.c \ + demioctl.c \ + demlock.c \ + demmisc.c \ + demmsg.c \ + demsrch.c \ + demdasd.c \ + demlabel.c + +I386_SOURCES= +MIPS_SOURCES= + +C_DEFINES=-DWIN_32 + +UMTYPE=console +UMTEST= +UMLIBS= |