summaryrefslogtreecommitdiffstats
path: root/private/mvdm/dos/dem
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/mvdm/dos/dem/dem.c76
-rw-r--r--private/mvdm/dos/dem/dem.h260
-rw-r--r--private/mvdm/dos/dem/demdasd.c734
-rw-r--r--private/mvdm/dos/dem/demdasd.h301
-rw-r--r--private/mvdm/dos/dem/demdata.c24
-rw-r--r--private/mvdm/dos/dem/demdir.c182
-rw-r--r--private/mvdm/dos/dem/demdisp.c245
-rw-r--r--private/mvdm/dos/dem/demerror.c388
-rw-r--r--private/mvdm/dos/dem/demfcb.c768
-rw-r--r--private/mvdm/dos/dem/demfile.c1160
-rw-r--r--private/mvdm/dos/dem/demgset.c1013
-rw-r--r--private/mvdm/dos/dem/demhndl.c605
-rw-r--r--private/mvdm/dos/dem/demioctl.c583
-rw-r--r--private/mvdm/dos/dem/demlabel.c76
-rw-r--r--private/mvdm/dos/dem/demlock.c62
-rw-r--r--private/mvdm/dos/dem/demmisc.c644
-rw-r--r--private/mvdm/dos/dem/demmsg.c48
-rw-r--r--private/mvdm/dos/dem/demmsg.h18
-rw-r--r--private/mvdm/dos/dem/demsrch.c2442
-rw-r--r--private/mvdm/dos/dem/dosdef.h140
-rw-r--r--private/mvdm/dos/dem/makefile9
-rw-r--r--private/mvdm/dos/dem/sources65
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=