/*
* DOS interrupt 21h handler
+ *
+ * Copyright 1993, 1994 Erik Bos
+ * Copyright 1996 Alexandre Julliard
+ * Copyright 1997 Andreas Mohr
+ * Copyright 1998 Uwe Bonnes
+ * Copyright 1998, 1999 Ove Kaaven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "config.h"
+
#include <time.h>
#include <fcntl.h>
#include <errno.h>
-#include <stdio.h>
#include <stdlib.h>
-#include <sys/file.h>
+#include <stdio.h>
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
#include <string.h>
-#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <utime.h>
#include <ctype.h>
-#include "windows.h"
-#include "dos_fs.h"
+#include "windef.h"
+#include "winbase.h"
+#include "ntddk.h"
+#include "wingdi.h"
+#include "winuser.h" /* SW_NORMAL */
+#include "wine/winbase16.h"
+#include "winerror.h"
#include "drive.h"
#include "file.h"
+#include "callback.h"
#include "msdos.h"
-#include "ldt.h"
-#include "task.h"
-#include "options.h"
#include "miscemu.h"
-#include "xmalloc.h"
-#include "stddebug.h"
-#include "debug.h"
+#include "task.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(int21);
#if defined(__svr4__) || defined(_SCO_DS)
/* SVR4 DOESNT do locking the same way must implement properly */
#define LOCK_EX 0
WORD free_clusters; /* Number of free clusters (0xFFFF=unknown) */
};
+struct EDPB /* FAT32 extended Drive Parameter Block */
+{ /* from Ralf Brown's Interrupt List */
+ struct DPB dpb; /* first 24 bytes = original DPB */
+
+ BYTE edpb_flags; /* undocumented/unknown flags */
+ DWORD next_edpb; /* pointer to next EDPB */
+ WORD free_cluster; /* cluster to start search for free space on write, typically
+ the last cluster allocated */
+ WORD clusters_free; /* number of free clusters on drive or FFFF = unknown */
+ WORD clusters_free_hi; /* hiword of clusters_free */
+ WORD mirroring_flags; /* mirroring flags: bit 7 set = do not mirror active FAT */
+ /* bits 0-3 = 0-based number of the active FAT */
+ WORD info_sector; /* sector number of file system info sector, or FFFF for none */
+ WORD spare_boot_sector; /* sector number of backup boot sector, or FFFF for none */
+ DWORD first_cluster; /* sector number of the first cluster */
+ DWORD max_cluster; /* sector number of the last cluster */
+ DWORD fat_clusters; /* number of clusters occupied by FAT */
+ DWORD root_cluster; /* cluster number of start of root directory */
+ DWORD free_cluster2; /* same as free_cluster: cluster at which to start
+ search for free space when writing */
+
+};
+
WORD CodePage = 437;
DWORD dpbsegptr;
BYTE mediaID;
BYTE biosdate[8];
struct DPB dpb;
+ BYTE DummyDBCSLeadTable[6];
};
static struct DosHeap *heap;
static WORD DosHeapHandle;
-WORD sharing_retries = 3; /* number of retries at sharing violation */
-WORD sharing_pause = 1; /* pause between retries */
-
extern char TempDirectory[];
-static BOOL32 INT21_CreateHeap(void)
+static void INT21_ReadConfigSys(void)
+{
+ static int done;
+ if (!done) DOSCONF_ReadConfig();
+ done = 1;
+}
+
+static BOOL INT21_CreateHeap(void)
{
if (!(DosHeapHandle = GlobalAlloc16(GMEM_FIXED,sizeof(struct DosHeap))))
{
- fprintf( stderr, "INT21_Init: Out of memory\n");
+ WARN("Out of memory\n");
return FALSE;
}
heap = (struct DosHeap *) GlobalLock16(DosHeapHandle);
- dpbsegptr = PTR_SEG_OFF_TO_SEGPTR(DosHeapHandle,(int)&heap->dpb-(int)heap);
+ dpbsegptr = MAKESEGPTR(DosHeapHandle,(int)&heap->dpb-(int)heap);
heap->InDosFlag = 0;
strcpy(heap->biosdate, "01/01/80");
+ memset(heap->DummyDBCSLeadTable, 0, 6);
return TRUE;
}
-BYTE *GetCurrentDTA(void)
+static BYTE *GetCurrentDTA( CONTEXT86 *context )
{
- TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
- return (BYTE *)PTR_SEG_TO_LIN( pTask->dta );
-}
-
+ TDB *pTask = TASK_GetCurrent();
-void ChopOffWhiteSpace(char *string)
-{
- int length;
-
- for (length = strlen(string) ; length ; length--)
- if (string[length] == ' ')
- string[length] = '\0';
+ /* FIXME: This assumes DTA was set correctly! */
+ return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta),
+ (DWORD)OFFSETOF(pTask->dta) );
}
-void CreateBPB(int drive, BYTE *data)
+
+void CreateBPB(int drive, BYTE *data, BOOL16 limited)
+/* limited == TRUE is used with INT 0x21/0x440d */
{
if (drive > 1) {
setword(data, 512);
setword(&data[0x0d], 56);
setword(&data[0x0f], 2);
setword(&data[0x11], 0);
- setword(&data[0x1f], 800);
- data[0x21] = 5;
- setword(&data[0x22], 1);
+ if (!limited) {
+ setword(&data[0x1f], 800);
+ data[0x21] = 5;
+ setword(&data[0x22], 1);
+ }
} else { /* 1.44mb */
setword(data, 512);
data[2] = 2;
setword(&data[0x0d], 18);
setword(&data[0x0f], 2);
setword(&data[0x11], 0);
- setword(&data[0x1f], 80);
- data[0x21] = 7;
- setword(&data[0x22], 2);
- }
+ if (!limited) {
+ setword(&data[0x1f], 80);
+ data[0x21] = 7;
+ setword(&data[0x22], 2);
+ }
+ }
}
-static int INT21_GetFreeDiskSpace( CONTEXT *context )
+static int INT21_GetFreeDiskSpace( CONTEXT86 *context )
{
DWORD cluster_sectors, sector_bytes, free_clusters, total_clusters;
char root[] = "A:\\";
*root += DOS_GET_DRIVE( DL_reg(context) );
- if (!GetDiskFreeSpace32A( root, &cluster_sectors, §or_bytes,
+ if (!GetDiskFreeSpaceA( root, &cluster_sectors, §or_bytes,
&free_clusters, &total_clusters )) return 0;
AX_reg(context) = cluster_sectors;
BX_reg(context) = free_clusters;
return 1;
}
-static int INT21_GetDriveAllocInfo( CONTEXT *context )
+static int INT21_GetDriveAllocInfo( CONTEXT86 *context )
{
if (!INT21_GetFreeDiskSpace( context )) return 0;
if (!heap && !INT21_CreateHeap()) return 0;
heap->mediaID = 0xf0;
- DS_reg(context) = DosHeapHandle;
+ context->SegDs = DosHeapHandle;
BX_reg(context) = (int)&heap->mediaID - (int)heap;
return 1;
}
-static void GetDrivePB( CONTEXT *context, int drive )
+static int FillInDrivePB( int drive )
{
if(!DRIVE_IsValid(drive))
{
- DOS_ERROR( ER_InvalidDrive, EC_MediaError, SA_Abort, EL_Disk );
- AX_reg(context) = 0x00ff;
+ SetLastError( ERROR_INVALID_DRIVE );
+ return 0;
}
else if (heap || INT21_CreateHeap())
{
- dprintf_int(stddeb, "int21: GetDrivePB not fully implemented.\n");
-
/* FIXME: I have no idea what a lot of this information should
* say or whether it even really matters since we're not allowing
* direct block access. However, some programs seem to depend on
heap->dpb.next = 0;
heap->dpb.free_search = 0;
heap->dpb.free_clusters = 0xFFFF; /* unknown */
+ return 1;
+ }
+
+ return 0;
+}
+static void GetDrivePB( CONTEXT86 *context, int drive )
+{
+ if (FillInDrivePB( drive ))
+ {
AL_reg(context) = 0x00;
- DS_reg(context) = SELECTOROF(dpbsegptr);
+ context->SegDs = SELECTOROF(dpbsegptr);
BX_reg(context) = OFFSETOF(dpbsegptr);
}
+ else
+ {
+ AX_reg(context) = 0x00ff;
+ }
}
-static void ioctlGetDeviceInfo( CONTEXT *context )
+static void ioctlGetDeviceInfo( CONTEXT86 *context )
{
- dprintf_int (stddeb, "int21: ioctl (%d, GetDeviceInfo)\n", BX_reg(context));
-
- DX_reg(context) = 0x0942;
+ int curr_drive;
+ const DOS_DEVICE *dev;
+
+ TRACE("(%d)\n", BX_reg(context));
+
+ RESET_CFLAG(context);
+
+ /* DOS device ? */
+ if ((dev = DOSFS_GetDeviceByHandle( DosFileHandleToWin32Handle(BX_reg(context)) )))
+ {
+ DX_reg(context) = dev->flags;
+ return;
+ }
+
+ /* it seems to be a file */
+ curr_drive = DRIVE_GetCurrentDrive();
+ DX_reg(context) = 0x0140 + curr_drive + ((curr_drive > 1) ? 0x0800 : 0);
+ /* no floppy */
/* bits 0-5 are current drive
* bit 6 - file has NOT been written..FIXME: correct?
* bit 8 - generate int24 if no diskspace on write/ read past end of file
* bit 11 - media not removable
+ * bit 14 - don't set file date/time on closing
+ * bit 15 - file is remote
*/
- RESET_CFLAG(context);
}
-static void ioctlGenericBlkDevReq( CONTEXT *context )
+static BOOL ioctlGenericBlkDevReq( CONTEXT86 *context )
{
- BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+ BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
int drive = DOS_GET_DRIVE( BL_reg(context) );
if (!DRIVE_IsValid(drive))
{
- DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- return;
+ SetLastError( ERROR_FILE_NOT_FOUND );
+ return TRUE;
}
if (CH_reg(context) != 0x08)
{
INT_BARF( context, 0x21 );
- return;
+ return FALSE;
}
- switch (CL_reg(context)) {
+
+ switch (CL_reg(context))
+ {
case 0x4a: /* lock logical volume */
- dprintf_int(stddeb,"int21: lock logical volume (%d) level %d mode %d\n",drive,BH_reg(context),DX_reg(context));
- return;
+ TRACE("lock logical volume (%d) level %d mode %d\n",drive,BH_reg(context),DX_reg(context));
+ break;
+
case 0x60: /* get device parameters */
/* used by w4wgrp's winfile */
- memset(dataptr, 0, 0x26);
+ memset(dataptr, 0, 0x20); /* DOS 6.22 uses 0x20 bytes */
dataptr[0] = 0x04;
dataptr[6] = 0; /* media type */
- if (drive > 1)
+ if (drive > 1)
{
dataptr[1] = 0x05; /* fixed disk */
setword(&dataptr[2], 0x01); /* non removable */
setword(&dataptr[2], 0x02); /* removable */
setword(&dataptr[4], 80); /* # of cylinders */
}
- CreateBPB(drive, &dataptr[7]);
+ CreateBPB(drive, &dataptr[7], TRUE);
RESET_CFLAG(context);
- return;
+ break;
+
+ case 0x41: /* write logical device track */
+ case 0x61: /* read logical device track */
+ {
+ BYTE drive = BL_reg(context) ?
+ BL_reg(context) : DRIVE_GetCurrentDrive();
+ WORD head = *(WORD *)dataptr+1;
+ WORD cyl = *(WORD *)dataptr+3;
+ WORD sect = *(WORD *)dataptr+5;
+ WORD nrsect = *(WORD *)dataptr+7;
+ BYTE *data = (BYTE *)dataptr+9;
+ int (*raw_func)(BYTE, DWORD, DWORD, BYTE *, BOOL);
+
+ raw_func = (CL_reg(context) == 0x41) ?
+ DRIVE_RawWrite : DRIVE_RawRead;
+
+ if (raw_func(drive, head*cyl*sect, nrsect, data, FALSE))
+ RESET_CFLAG(context);
+ else
+ {
+ AX_reg(context) = 0x1e; /* read fault */
+ SET_CFLAG(context);
+ }
+ }
+ break;
case 0x66:/* get disk serial number */
- { char label[12],fsname[9],path[4];
+ {
+ char label[12],fsname[9],path[4];
DWORD serial;
strcpy(path,"x:\\");path[0]=drive+'A';
- GetVolumeInformation32A(
+ GetVolumeInformationA(
path,label,12,&serial,NULL,NULL,fsname,9
);
*(WORD*)dataptr = 0;
memcpy(dataptr+2,&serial,4);
memcpy(dataptr+6,label ,11);
memcpy(dataptr+17,fsname,8);
- return;
}
+ break;
+
case 0x6a:
- dprintf_int(stddeb,"int21: logical volume %d unlocked.\n",drive);
- return;
+ TRACE("logical volume %d unlocked.\n",drive);
+ break;
+
+ case 0x6f:
+ memset(dataptr+1, '\0', dataptr[0]-1);
+ dataptr[1] = dataptr[0];
+ dataptr[2] = 0x07; /* protected mode driver; no eject; no notification */
+ dataptr[3] = 0xFF; /* no physical drive */
+ break;
+
+ case 0x72:
+ /* Trail on error implementation */
+ AX_reg(context) = GetDriveType16(BL_reg(context)) == DRIVE_UNKNOWN ? 0x0f : 0x01;
+ SET_CFLAG(context); /* Seems to be set all the time */
+ break;
+
default:
INT_BARF( context, 0x21 );
}
+ return FALSE;
}
-static void GetSystemDate( CONTEXT *context )
+static void INT21_ParseFileNameIntoFCB( CONTEXT86 *context )
{
- struct tm *now;
- time_t ltime;
+ char *filename =
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi );
+ char *fcb =
+ CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi );
+ char *buffer, *s, *d;
- ltime = time(NULL);
- now = localtime(<ime);
+ AL_reg(context) = 0xff; /* failed */
- CX_reg(context) = now->tm_year + 1900;
- DX_reg(context) = ((now->tm_mon + 1) << 8) | now->tm_mday;
- AX_reg(context) = now->tm_wday;
-}
+ TRACE("filename: '%s'\n", filename);
-static void INT21_GetSystemTime( CONTEXT *context )
-{
- struct tm *now;
- struct timeval tv;
- time_t seconds;
-
- gettimeofday(&tv,NULL); /* Note use of gettimeofday(), instead of time() */
- seconds = tv.tv_sec;
- now = localtime(&seconds);
-
- CX_reg(context) = (now->tm_hour<<8) | now->tm_min;
- DX_reg(context) = (now->tm_sec<<8) | tv.tv_usec/10000;
- /* Note hundredths of seconds */
-}
+ buffer = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 1);
-static void INT21_CreateFile( CONTEXT *context )
-{
- AX_reg(context) = _lcreat16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) ), CX_reg(context) );
- if (AX_reg(context) == (WORD)HFILE_ERROR16)
+ s = filename;
+ d = buffer;
+ while (*s)
{
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
+ if ((*s != ' ') && (*s != '\r') && (*s != '\n'))
+ *d++ = *s++;
+ else
+ break;
}
-}
+ *d = '\0';
+ DOSFS_ToDosFCBFormat(buffer, fcb + 1);
+ *fcb = 0;
+ TRACE("FCB: '%s'\n", ((CHAR *)fcb + 1));
-void OpenExistingFile( CONTEXT *context )
-{
- AX_reg(context) = _lopen16( PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
- AL_reg(context) );
- if (AX_reg(context) == (WORD)HFILE_ERROR16)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
-#if 0
- int handle;
- int mode;
- int lock;
-
- dprintf_int (stddeb, "int21: open (%s, %d) = %d\n",
- DOS_GetUnixFileName(PTR_SEG_OFF_TO_LIN(DS_reg(context),
- DX_reg(context))), mode, handle);
-
- switch (AX_reg(context) & 0x0070)
- {
- case 0x00: /* compatability mode */
- case 0x40: /* DENYNONE */
- lock = -1;
- break;
+ HeapFree( GetProcessHeap(), 0, buffer);
- case 0x30: /* DENYREAD */
- dprintf_int(stddeb,
- "OpenExistingFile (%s): DENYREAD changed to DENYALL\n",
- (char *)PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)));
- case 0x10: /* DENYALL */
- lock = LOCK_EX;
- break;
+ AL_reg(context) =
+ ((strchr(filename, '*')) || (strchr(filename, '$'))) != 0;
- case 0x20: /* DENYWRITE */
- lock = LOCK_SH;
- break;
+ /* point DS:SI to first unparsed character */
+ SI_reg(context) += (int)s - (int)filename;
+}
- default:
- lock = -1;
- }
+static void INT21_GetSystemDate( CONTEXT86 *context )
+{
+ SYSTEMTIME systime;
+ GetLocalTime( &systime );
+ CX_reg(context) = systime.wYear;
+ DX_reg(context) = (systime.wMonth << 8) | systime.wDay;
+ AX_reg(context) = systime.wDayOfWeek;
+}
- if (lock != -1)
- {
+static void INT21_GetSystemTime( CONTEXT86 *context )
+{
+ SYSTEMTIME systime;
+ GetLocalTime( &systime );
+ CX_reg(context) = (systime.wHour << 8) | systime.wMinute;
+ DX_reg(context) = (systime.wSecond << 8) | (systime.wMilliseconds / 10);
+}
- int result,retries=sharing_retries;
- {
-#if defined(__svr4__) || defined(_SCO_DS)
- printf("Should call flock and needs porting to lockf\n");
- result = 0;
- retries = 0;
-#else
- result = flock(handle, lock | LOCK_NB);
-#endif
- if ( retries && (!result) )
- {
- int i;
- for(i=0;i<32768*((int)sharing_pause);i++)
- result++; /* stop the optimizer */
- for(i=0;i<32768*((int)sharing_pause);i++)
- result--;
- }
- }
- while( (!result) && (!(retries--)) );
+/* Many calls translate a drive argument like this:
+ drive number (00h = default, 01h = A:, etc)
+ */
+static char drivestring[]="default";
- if(result)
- {
- errno_to_doserr();
- AX_reg(context) = ExtendedError;
- close(handle);
- SET_CFLAG(context);
- return;
- }
+char *INT21_DriveName(int drive)
+{
- }
+ if(drive >0)
+ {
+ drivestring[0]= (unsigned char)drive + '@';
+ drivestring[1]=':';
+ drivestring[2]=0;
+ }
+ return drivestring;
+}
+static BOOL INT21_CreateFile( CONTEXT86 *context )
+{
+ AX_reg(context) = _lcreat16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx ), CX_reg(context) );
+ return (AX_reg(context) == (WORD)HFILE_ERROR16);
+}
- Error (0,0,0);
- AX_reg(context) = handle;
- RESET_CFLAG(context);
-#endif
+static HFILE16 _lcreat16_uniq( LPCSTR path, INT attr )
+{
+ /* Mask off all flags not explicitly allowed by the doc */
+ attr &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
+ return Win32HandleToDosFileHandle( CreateFileA( path, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ CREATE_NEW, attr, 0 ));
}
-static void CloseFile( CONTEXT *context )
+static void OpenExistingFile( CONTEXT86 *context )
{
- if ((AX_reg(context) = _lclose16( BX_reg(context) )) != 0)
+ AX_reg(context) = _lopen16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
+ AL_reg(context) );
+ if (AX_reg(context) == (WORD)HFILE_ERROR16)
{
- AX_reg(context) = DOS_ExtendedError;
+ AX_reg(context) = GetLastError();
SET_CFLAG(context);
}
}
-void ExtendedOpenCreateFile(CONTEXT *context )
+static BOOL INT21_ExtendedOpenCreateFile(CONTEXT86 *context )
{
- BYTE action=DL_reg(context);
- dprintf_int(stddeb, "int21: extended open/create: file= %s \n",
- DOSFS_GetUnixFileName(PTR_SEG_OFF_TO_LIN(DS_reg(context),SI_reg(context)),FALSE));
+ BOOL bExtendedError = FALSE;
+ BYTE action = DL_reg(context);
+
/* Shuffle arguments to call OpenExistingFile */
AL_reg(context) = BL_reg(context);
DX_reg(context) = SI_reg(context);
/* BX,CX and DX should be preserved */
OpenExistingFile(context);
- if ((EFL_reg(context) & 0x0001)==0)
- { /* It exists */
- dprintf_int(stddeb, "int21: extended open/create %s exists \n",
- DOSFS_GetUnixFileName(PTR_SEG_OFF_TO_LIN(DS_reg(context),SI_reg(context)),TRUE));
+
+ if ((context->EFlags & 0x0001) == 0) /* File exists */
+ {
+ UINT16 uReturnCX = 0;
+
/* Now decide what do do */
- if ((action & 0x07)== 0)
- {
- BX_reg(context) = AX_reg(context);
- CloseFile(context);
- AX_reg(context) = 0x0050;/*File exists*/
- CX_reg(context) = 0;
- SET_CFLAG(context);
- dprintf_int(stddeb, "int21: extended open/create: failed because file exixts \n");
- return;
- }
- if ((action & 0x07)== 2) {
- /* Truncate it, but first check if opend for write */
- if ((BL_reg(context) & 0x0007)== 0) {
- BX_reg(context) = AX_reg(context);
- CloseFile(context);
- dprintf_int(stddeb, "int21: extended open/create: failed, trunc on ro file");
- AX_reg(context) = 0x000C;/*Access code invalid*/
- CX_reg(context) = 0;
- SET_CFLAG(context);
- return;
- }
- /* Shuffle arguments to call CloseFile */
- dprintf_int(stddeb, "int21: extended open/create: Closing before truncate\n");
- BX_reg(context) = AX_reg(context);
- /* BX and DX should be preserved */
- CloseFile(context);
- if (EFL_reg(context) & 0x0001) {
- dprintf_int(stddeb, "int21: extended open/create: close before trunc failed");
- AX_reg(context) = 0x0019;/*Seek Error*/
- CX_reg(context) = 0;
+
+ if ((action & 0x07) == 0)
+ {
+ _lclose16( AX_reg(context) );
+ AX_reg(context) = 0x0050; /*File exists*/
SET_CFLAG(context);
+ WARN("extended open/create: failed because file exists \n");
+ }
+ else if ((action & 0x07) == 2)
+ {
+ /* Truncate it, but first check if opened for write */
+ if ((BL_reg(context) & 0x0007)== 0)
+ {
+ _lclose16( AX_reg(context) );
+ WARN("extended open/create: failed, trunc on ro file\n");
+ AX_reg(context) = 0x000C; /*Access code invalid*/
+ SET_CFLAG(context);
}
- /* Shuffle arguments to call CreateFile */
- dprintf_int(stddeb, "int21: extended open/create: Truncating\n");
- AL_reg(context) = BL_reg(context);
- /* CX is still the same */
- DX_reg(context) = SI_reg(context);
- INT21_CreateFile(context);
- if (EFL_reg(context) & 0x0001) { /*no file open, flags set */
- dprintf_int(stddeb, "int21: extended open/create: truncfailed");
- return;
+ else
+ {
+ TRACE("extended open/create: Closing before truncate\n");
+ if (_lclose16( AX_reg(context) ))
+ {
+ WARN("extended open/create: close before trunc failed\n");
+ AX_reg(context) = 0x0019; /*Seek Error*/
+ CX_reg(context) = 0;
+ SET_CFLAG(context);
+ }
+ /* Shuffle arguments to call CreateFile */
+
+ TRACE("extended open/create: Truncating\n");
+ AL_reg(context) = BL_reg(context);
+ /* CX is still the same */
+ DX_reg(context) = SI_reg(context);
+ bExtendedError = INT21_CreateFile(context);
+
+ if (context->EFlags & 0x0001) /*no file open, flags set */
+ {
+ WARN("extended open/create: trunc failed\n");
+ return bExtendedError;
+ }
+ uReturnCX = 0x3;
}
- CX_reg(context) = 3;
- return;
}
- CX_reg(context) = 1;
- return;
- }
+ else uReturnCX = 0x1;
+
+ CX_reg(context) = uReturnCX;
+ }
else /* file does not exist */
- {
+ {
RESET_CFLAG(context); /* was set by OpenExistingFile(context) */
- dprintf_int(stddeb, "int21: extended open/create %s dosen't exists \n",
- DOSFS_GetUnixFileName(PTR_SEG_OFF_TO_LIN(DS_reg(context),SI_reg(context)),FALSE));
- if ((action & 0xF0)== 0) {
+ if ((action & 0xF0)== 0)
+ {
CX_reg(context) = 0;
SET_CFLAG(context);
- dprintf_int(stddeb, "int21: extended open/create: failed, file dosen't exist\n");
- return;
+ WARN("extended open/create: failed, file dosen't exist\n");
}
- /* Shuffle arguments to call CreateFile */
- dprintf_int(stddeb, "int21: extended open/create: Creating\n");
- AL_reg(context) = BL_reg(context);
- /* CX should still be the same */
- DX_reg(context) = SI_reg(context);
- INT21_CreateFile(context);
- if (EFL_reg(context) & 0x0001) { /*no file open, flags set */
- dprintf_int(stddeb, "int21: extended open/create: create failed\n");
- return;
+ else
+ {
+ /* Shuffle arguments to call CreateFile */
+ TRACE("extended open/create: Creating\n");
+ AL_reg(context) = BL_reg(context);
+ /* CX should still be the same */
+ DX_reg(context) = SI_reg(context);
+ bExtendedError = INT21_CreateFile(context);
+ if (context->EFlags & 0x0001) /*no file open, flags set */
+ {
+ WARN("extended open/create: create failed\n");
+ return bExtendedError;
+ }
+ CX_reg(context) = 2;
}
- CX_reg(context) = 2;
- return;
- }
-}
+ }
-
-static int INT21_RenameFile( CONTEXT *context )
-{
- const char *newname, *oldname;
- char *buffer;
-
- /* FIXME: should not rename over an existing file */
- dprintf_int(stddeb,"int21: renaming %s to %s\n",
- (char *)PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
- (char *)PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context)));
-
- oldname = DOSFS_GetUnixFileName( PTR_SEG_OFF_TO_LIN(DS_reg(context),
- DX_reg(context)), TRUE );
- if (!oldname) return 0;
- buffer = xstrdup( oldname );
- newname = DOSFS_GetUnixFileName( PTR_SEG_OFF_TO_LIN(ES_reg(context),
- DI_reg(context)), FALSE );
- if (!newname)
- {
- free( buffer );
- return 0;
- }
-
- if (rename( buffer, newname) == -1)
- {
- FILE_SetDosError();
- free( buffer );
- return 0;
- }
- free( buffer );
- return 1;
+ return bExtendedError;
}
-static void INT21_ChangeDir( CONTEXT *context )
+static BOOL INT21_ChangeDir( CONTEXT86 *context )
{
int drive;
- char *dirname = PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context));
+ char *dirname = CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx);
- dprintf_int(stddeb,"int21: changedir %s\n", dirname);
+ TRACE("changedir %s\n", dirname);
if (dirname[0] && (dirname[1] == ':'))
{
drive = toupper(dirname[0]) - 'A';
dirname += 2;
}
else drive = DRIVE_GetCurrentDrive();
- if (!DRIVE_Chdir( drive, dirname ))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ return DRIVE_Chdir( drive, dirname );
}
-static int INT21_FindFirst( CONTEXT *context )
+static int INT21_FindFirst( CONTEXT86 *context )
{
- const char *path, *unixPath, *mask;
char *p;
- FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA();
+ const char *path;
+ DOS_FULL_NAME full_name;
+ FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
- path = (const char *)PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+ path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
dta->unixPath = NULL;
- if (!(unixPath = DOSFS_GetUnixFileName( path, FALSE )))
+ if (!DOSFS_GetFullName( path, FALSE, &full_name ))
{
- AX_reg(context) = DOS_ExtendedError;
+ AX_reg(context) = GetLastError();
SET_CFLAG(context);
return 0;
}
- dta->unixPath = xstrdup( unixPath );
+ dta->unixPath = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
+ strcpy( dta->unixPath, full_name.long_name );
p = strrchr( dta->unixPath, '/' );
*p = '\0';
- if (!(mask = DOSFS_ToDosFCBFormat( p + 1 )))
+
+ /* Note: terminating NULL in dta->mask overwrites dta->search_attr
+ * (doesn't matter as it is set below anyway)
+ */
+ if (!DOSFS_ToDosFCBFormat( p + 1, dta->mask ))
{
- free( dta->unixPath );
+ HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
- DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
- AX_reg(context) = ER_FileNotFound;
+ SetLastError( ERROR_FILE_NOT_FOUND );
+ AX_reg(context) = ERROR_FILE_NOT_FOUND;
SET_CFLAG(context);
return 0;
}
- memcpy( dta->mask, mask, sizeof(dta->mask) );
dta->drive = (path[0] && (path[1] == ':')) ? toupper(path[0]) - 'A'
: DRIVE_GetCurrentDrive();
dta->count = 0;
}
-static int INT21_FindNext( CONTEXT *context )
+static int INT21_FindNext( CONTEXT86 *context )
{
- FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA();
- WIN32_FIND_DATA32A entry;
+ FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
+ WIN32_FIND_DATAA entry;
int count;
if (!dta->unixPath) return 0;
if (!(count = DOSFS_FindNext( dta->unixPath, dta->mask, NULL, dta->drive,
dta->search_attr, dta->count, &entry )))
{
- free( dta->unixPath );
+ HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
return 0;
}
if ((int)dta->count + count > 0xffff)
{
- fprintf( stderr, "Too many directory entries in %s\n", dta->unixPath );
- free( dta->unixPath );
+ WARN("Too many directory entries in %s\n", dta->unixPath );
+ HeapFree( GetProcessHeap(), 0, dta->unixPath );
dta->unixPath = NULL;
return 0;
}
FileTimeToDosDateTime( &entry.ftLastWriteTime,
&dta->filedate, &dta->filetime );
strcpy( dta->filename, entry.cAlternateFileName );
+ if (!memchr(dta->mask,'?',11)) {
+ /* wildcardless search, release resources in case no findnext will
+ * be issued, and as a workaround in case file creation messes up
+ * findnext, as sometimes happens with pkunzip */
+ HeapFree( GetProcessHeap(), 0, dta->unixPath );
+ dta->unixPath = NULL;
+ }
return 1;
}
-static int INT21_CreateTempFile( CONTEXT *context )
+static BOOL INT21_CreateTempFile( CONTEXT86 *context )
{
static int counter = 0;
- char *name = PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context) );
+ char *name = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx );
char *p = name + strlen(name);
+ /* despite what Ralf Brown says, some programs seem to call without
+ * ending backslash (DOS accepts that, so we accept it too) */
+ if ((p == name) || (p[-1] != '\\')) *p++ = '\\';
+
for (;;)
{
sprintf( p, "wine%04x.%03d", (int)getpid(), counter );
counter = (counter + 1) % 1000;
- if ((AX_reg(context) = _lcreat_uniq( name, 0 )) != (WORD)HFILE_ERROR16)
+ if ((AX_reg(context) = _lcreat16_uniq( name, 0 )) != (WORD)HFILE_ERROR16)
{
- dprintf_int( stddeb, "INT21_CreateTempFile: created %s\n", name );
- return 1;
+ TRACE("created %s\n", name );
+ return TRUE;
}
- if (DOS_ExtendedError != ER_FileExists) return 0;
+ if (GetLastError() != ERROR_FILE_EXISTS) return FALSE;
}
}
-static int INT21_GetCurrentDirectory( CONTEXT *context )
+static BOOL INT21_GetCurrentDirectory( CONTEXT86 *context )
{
int drive = DOS_GET_DRIVE( DL_reg(context) );
- char *ptr = (char *)PTR_SEG_OFF_TO_LIN( DS_reg(context), SI_reg(context) );
+ char *ptr = (char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi );
if (!DRIVE_IsValid(drive))
{
- DOS_ERROR( ER_InvalidDrive, EC_NotFound, SA_Abort, EL_Disk );
- return 0;
+ SetLastError( ERROR_INVALID_DRIVE );
+ return FALSE;
}
+ lstrcpynA( ptr, DRIVE_GetDosCwd(drive), 64 );
+ AX_reg(context) = 0x0100; /* success return code */
+ return TRUE;
+}
- lstrcpyn32A( ptr, DRIVE_GetDosCwd(drive), 64 );
- return 1;
+
+static void INT21_GetDBCSLeadTable( CONTEXT86 *context )
+{
+ if (heap || INT21_CreateHeap())
+ { /* return an empty table just as DOS 4.0+ does */
+ context->SegDs = DosHeapHandle;
+ SI_reg(context) = (int)&heap->DummyDBCSLeadTable - (int)heap;
+ }
+ else
+ {
+ AX_reg(context) = 0x1; /* error */
+ SET_CFLAG(context);
+ }
}
-static int INT21_GetDiskSerialNumber( CONTEXT *context )
+static int INT21_GetDiskSerialNumber( CONTEXT86 *context )
{
- BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+ BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
int drive = DOS_GET_DRIVE( BL_reg(context) );
-
+
if (!DRIVE_IsValid(drive))
{
- DOS_ERROR( ER_InvalidDrive, EC_NotFound, SA_Abort, EL_Disk );
+ SetLastError( ERROR_INVALID_DRIVE );
return 0;
}
-
+
*(WORD *)dataptr = 0;
*(DWORD *)(dataptr + 2) = DRIVE_GetSerialNumber( drive );
memcpy( dataptr + 6, DRIVE_GetLabel( drive ), 11 );
}
-static int INT21_SetDiskSerialNumber( CONTEXT *context )
+static int INT21_SetDiskSerialNumber( CONTEXT86 *context )
{
- BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+ BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
int drive = DOS_GET_DRIVE( BL_reg(context) );
if (!DRIVE_IsValid(drive))
{
- DOS_ERROR( ER_InvalidDrive, EC_NotFound, SA_Abort, EL_Disk );
+ SetLastError( ERROR_INVALID_DRIVE );
return 0;
}
/* microsoft's programmers should be shot for using CP/M style int21
calls in Windows for Workgroup's winfile.exe */
-static int INT21_FindFirstFCB( CONTEXT *context )
+static int INT21_FindFirstFCB( CONTEXT86 *context )
{
- BYTE *fcb = (BYTE *)PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+ BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
FINDFILE_FCB *pFCB;
- BYTE attr;
- char buffer[] = "A:.";
- const char *unixPath;
-
- if (*fcb == 0xff)
- {
- attr = fcb[6];
- pFCB = (FINDFILE_FCB *)(fcb + 7);
- }
- else
- {
- attr = 0;
- pFCB = (FINDFILE_FCB *)fcb;
- }
+ LPCSTR root, cwd;
+ int drive;
- buffer[0] += DOS_GET_DRIVE( pFCB->drive );
- pFCB->unixPath = NULL;
- if (!(unixPath = DOSFS_GetUnixFileName( buffer, TRUE ))) return 0;
- pFCB->unixPath = xstrdup( unixPath );
+ if (*fcb == 0xff) pFCB = (FINDFILE_FCB *)(fcb + 7);
+ else pFCB = (FINDFILE_FCB *)fcb;
+ drive = DOS_GET_DRIVE( pFCB->drive );
+ if (!DRIVE_IsValid( drive )) return 0;
+ root = DRIVE_GetRoot( drive );
+ cwd = DRIVE_GetUnixCwd( drive );
+ pFCB->unixPath = HeapAlloc( GetProcessHeap(), 0,
+ strlen(root)+strlen(cwd)+2 );
+ if (!pFCB->unixPath) return 0;
+ strcpy( pFCB->unixPath, root );
+ strcat( pFCB->unixPath, "/" );
+ strcat( pFCB->unixPath, cwd );
pFCB->count = 0;
return 1;
}
-static int INT21_FindNextFCB( CONTEXT *context )
+static int INT21_FindNextFCB( CONTEXT86 *context )
{
- BYTE *fcb = (BYTE *)PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+ BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
FINDFILE_FCB *pFCB;
- DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA();
- WIN32_FIND_DATA32A entry;
+ DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
+ WIN32_FIND_DATAA entry;
BYTE attr;
int count;
- if (*fcb == 0xff)
+ if (*fcb == 0xff) /* extended FCB ? */
{
attr = fcb[6];
pFCB = (FINDFILE_FCB *)(fcb + 7);
DOS_GET_DRIVE( pFCB->drive ), attr,
pFCB->count, &entry )))
{
- free( pFCB->unixPath );
+ HeapFree( GetProcessHeap(), 0, pFCB->unixPath );
pFCB->unixPath = NULL;
return 0;
}
pFCB->count += count;
+ if (*fcb == 0xff) { /* place extended FCB header before pResult if called with extended FCB */
+ *(BYTE *)pResult = 0xff;
+ (BYTE *)pResult +=6; /* leave reserved field behind */
+ *(BYTE *)pResult = entry.dwFileAttributes;
+ ((BYTE *)pResult)++;
+ }
+ *(BYTE *)pResult = DOS_GET_DRIVE( pFCB->drive ); /* DOS_DIRENTRY_LAYOUT after current drive number */
+ ((BYTE *)pResult)++;
pResult->fileattr = entry.dwFileAttributes;
pResult->cluster = 0; /* what else? */
pResult->filesize = entry.nFileSizeLow;
if (p && p[1] && (p != entry.cAlternateFileName))
{
memcpy( pResult->filename, entry.cAlternateFileName,
- MIN( (p - entry.cAlternateFileName), 8 ) );
- memcpy( pResult->filename + 8, p + 1, MIN( strlen(p), 3 ) );
+ min( (p - entry.cAlternateFileName), 8 ) );
+ memcpy( pResult->filename + 8, p + 1, min( strlen(p), 3 ) );
}
else
memcpy( pResult->filename, entry.cAlternateFileName,
- MIN( strlen(entry.cAlternateFileName), 8 ) );
+ min( strlen(entry.cAlternateFileName), 8 ) );
}
return 1;
}
-static void DeleteFileFCB( CONTEXT *context )
+static void DeleteFileFCB( CONTEXT86 *context )
{
- fprintf( stderr, "DeleteFileFCB: not implemented yet\n" );
-#if 0
- BYTE *fcb = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
- struct dosdirent *dp;
- char temp[256], *ptr;
- int drive = DOS_GET_DRIVE( *fcb );
-
- DumpFCB( fcb );
-
- temp[0] = '\\';
- strcpy(temp+1, DRIVE_GetDosCwd(drive));
- strcat(temp, "\\");
- strncat(temp, fcb + 1, 8);
- ChopOffWhiteSpace(temp);
- strncat(temp, fcb + 9, 3);
- ChopOffWhiteSpace(temp);
-
- if ((dp = DOS_opendir(temp)) == NULL) {
- Error(InvalidDrive, EC_MediaError , EL_Disk);
- AX_reg(context) = 0xff;
- return;
- }
-
- temp[0] = '\\';
- strcpy(temp+1, DRIVE_GetDosCwd(drive) );
- strcat(temp, "\\");
-
- ptr = temp + strlen(temp);
-
- while (DOS_readdir(dp) != NULL)
- {
- strcpy(ptr, dp->filename);
- dprintf_int(stddeb, "int21: delete file %s\n", temp);
- /* unlink(DOS_GetUnixFileName(temp)); */
- }
- DOS_closedir(dp);
- AX_reg(context) = 0;
-#endif
+ FIXME("(%p): stub\n", context);
}
-static void RenameFileFCB( CONTEXT *context )
+static void RenameFileFCB( CONTEXT86 *context )
{
- fprintf( stderr, "RenameFileFCB: not implemented yet\n" );
-#if 0
- BYTE *fcb = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
- struct dosdirent *dp;
- char temp[256], oldname[256], newname[256], *oldnameptr, *newnameptr;
- int drive = DOS_GET_DRIVE( *fcb );
-
- DumpFCB( fcb );
-
- temp[0] = '\\';
- strcpy(temp+1, DRIVE_GetDosCwd(drive) );
- strcat(temp, "\\");
- strncat(temp, fcb + 1, 8);
- ChopOffWhiteSpace(temp);
- strncat(temp, fcb + 9, 3);
- ChopOffWhiteSpace(temp);
-
- if ((dp = DOS_opendir(temp)) == NULL) {
- Error(InvalidDrive, EC_MediaError , EL_Disk);
- AX_reg(context) = 0xff;
- return;
- }
-
- oldname[0] = '\\';
- strcpy(oldname+1, DRIVE_GetDosCwd(drive) );
- strcat(oldname, "\\");
- strcpy( newname, oldname );
- oldnameptr = oldname + strlen(oldname);
- newnameptr = newname + strlen(newname);
-
- while (DOS_readdir(dp) != NULL)
- {
- strcpy(oldnameptr, dp->filename);
- strcpy(newnameptr, fcb + 1);
- dprintf_int(stddeb, "int21: renamefile %s -> %s\n",
- oldname, newname);
- }
- DOS_closedir(dp);
- AX_reg(context) = 0;
-#endif
+ FIXME("(%p): stub\n", context);
}
-static void fLock( CONTEXT * context )
+static void fLock( CONTEXT86 * context )
{
-#if 0
- struct flock f;
- int result,retries=sharing_retries;
-
- f.l_start = MAKELONG(DX_reg(context),CX_reg(context));
- f.l_len = MAKELONG(DI_reg(context),SI_reg(context));
- f.l_whence = 0;
- f.l_pid = 0;
switch ( AX_reg(context) & 0xff )
{
case 0x00: /* LOCK */
- f.l_type = F_WRLCK;
+ TRACE("lock handle %d offset %ld length %ld\n",
+ BX_reg(context),
+ MAKELONG(DX_reg(context),CX_reg(context)),
+ MAKELONG(DI_reg(context),SI_reg(context))) ;
+ if (!LockFile(DosFileHandleToWin32Handle(BX_reg(context)),
+ MAKELONG(DX_reg(context),CX_reg(context)), 0,
+ MAKELONG(DI_reg(context),SI_reg(context)), 0)) {
+ AX_reg(context) = GetLastError();
+ SET_CFLAG(context);
+ }
break;
case 0x01: /* UNLOCK */
- f.l_type = F_UNLCK;
- break;
-
+ TRACE("unlock handle %d offset %ld length %ld\n",
+ BX_reg(context),
+ MAKELONG(DX_reg(context),CX_reg(context)),
+ MAKELONG(DI_reg(context),SI_reg(context))) ;
+ if (!UnlockFile(DosFileHandleToWin32Handle(BX_reg(context)),
+ MAKELONG(DX_reg(context),CX_reg(context)), 0,
+ MAKELONG(DI_reg(context),SI_reg(context)), 0)) {
+ AX_reg(context) = GetLastError();
+ SET_CFLAG(context);
+ }
+ return;
default:
AX_reg(context) = 0x0001;
SET_CFLAG(context);
return;
}
-
+}
+
+static BOOL
+INT21_networkfunc (CONTEXT86 *context)
+{
+ switch (AL_reg(context)) {
+ case 0x00: /* Get machine name. */
{
- result = fcntl(BX_reg(context),F_SETLK,&f);
- if ( retries && (!result) )
- {
- int i;
- for(i=0;i<32768*((int)sharing_pause);i++)
- result++; /* stop the optimizer */
- for(i=0;i<32768*((int)sharing_pause);i++)
- result--;
- }
- }
- while( (!result) && (!(retries--)) );
+ char *dst = CTX_SEG_OFF_TO_LIN (context,context->SegDs,context->Edx);
+ TRACE("getting machine name to %p\n", dst);
+ if (gethostname (dst, 15))
+ {
+ WARN("failed!\n");
+ SetLastError( ER_NoNetwork );
+ return TRUE;
+ } else {
+ int len = strlen (dst);
+ while (len < 15)
+ dst[len++] = ' ';
+ dst[15] = 0;
+ CH_reg(context) = 1; /* Valid */
+ CL_reg(context) = 1; /* NETbios number??? */
+ TRACE("returning %s\n", debugstr_an (dst, 16));
+ return FALSE;
+ }
+ }
- if(result)
- {
- FILE_SetDosError();
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- return;
- }
-#endif
-}
+ default:
+ SetLastError( ER_NoNetwork );
+ return TRUE;
+ }
+}
-static int INT21_GetFileAttribute( CONTEXT * context )
+static void ASPI_DOS_HandleInt( CONTEXT86 *context )
{
- const char *unixName;
- BY_HANDLE_FILE_INFORMATION info;
-
- unixName = DOSFS_GetUnixFileName( PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)), TRUE );
- if (!unixName) return 0;
- if (!FILE_Stat( unixName, &info )) return 0;
- CX_reg(context) = info.dwFileAttributes;
- dprintf_int( stddeb, "INT21_GetFileAttributes(%s) = 0x%x\n",
- unixName, CX_reg(context) );
- return 1;
+ if (!Dosvm.ASPIHandler && !DPMI_LoadDosSystem())
+ {
+ ERR("could not setup ASPI handler\n");
+ return;
+ }
+ Dosvm.ASPIHandler( context );
}
+/***********************************************************************
+ * INT21_GetExtendedError
+ */
+static void INT21_GetExtendedError( CONTEXT86 *context )
+{
+ BYTE class, action, locus;
+ WORD error = GetLastError();
-extern void LOCAL_PrintHeap (WORD ds);
+ switch(error)
+ {
+ case ERROR_SUCCESS:
+ class = action = locus = 0;
+ break;
+ case ERROR_DIR_NOT_EMPTY:
+ class = EC_Exists;
+ action = SA_Ignore;
+ locus = EL_Disk;
+ break;
+ case ERROR_ACCESS_DENIED:
+ class = EC_AccessDenied;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_CANNOT_MAKE:
+ class = EC_AccessDenied;
+ action = SA_Abort;
+ locus = EL_Unknown;
+ break;
+ case ERROR_DISK_FULL:
+ case ERROR_HANDLE_DISK_FULL:
+ class = EC_MediaError;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_FILE_EXISTS:
+ case ERROR_ALREADY_EXISTS:
+ class = EC_Exists;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_FILE_NOT_FOUND:
+ class = EC_NotFound;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ER_GeneralFailure:
+ class = EC_SystemFailure;
+ action = SA_Abort;
+ locus = EL_Unknown;
+ break;
+ case ERROR_INVALID_DRIVE:
+ class = EC_MediaError;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_INVALID_HANDLE:
+ class = EC_ProgramError;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_LOCK_VIOLATION:
+ class = EC_AccessDenied;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_NO_MORE_FILES:
+ class = EC_MediaError;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ER_NoNetwork:
+ class = EC_NotFound;
+ action = SA_Abort;
+ locus = EL_Network;
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ class = EC_OutOfResource;
+ action = SA_Abort;
+ locus = EL_Memory;
+ break;
+ case ERROR_PATH_NOT_FOUND:
+ class = EC_NotFound;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ case ERROR_SEEK:
+ class = EC_NotFound;
+ action = SA_Ignore;
+ locus = EL_Disk;
+ break;
+ case ERROR_SHARING_VIOLATION:
+ class = EC_Temporary;
+ action = SA_Retry;
+ locus = EL_Disk;
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ class = EC_ProgramError;
+ action = SA_Abort;
+ locus = EL_Disk;
+ break;
+ default:
+ FIXME("Unknown error %d\n", error );
+ class = EC_SystemFailure;
+ action = SA_Abort;
+ locus = EL_Unknown;
+ break;
+ }
+ TRACE("GET EXTENDED ERROR code 0x%02x class 0x%02x action 0x%02x locus %02x\n",
+ error, class, action, locus );
+ AX_reg(context) = error;
+ BH_reg(context) = class;
+ BL_reg(context) = action;
+ CH_reg(context) = locus;
+}
/***********************************************************************
- * DOS3Call (KERNEL.102)
+ * DOS3Call (KERNEL.102)
+ * INT_Int21Handler (WPROCS.133)
*/
-void DOS3Call( CONTEXT *context )
+void WINAPI DOS3Call( CONTEXT86 *context )
{
- dprintf_int( stddeb, "int21: AX=%04x BX=%04x CX=%04x DX=%04x "
- "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08lx\n",
- AX_reg(context), BX_reg(context), CX_reg(context),
- DX_reg(context), SI_reg(context), DI_reg(context),
- (WORD)DS_reg(context), (WORD)ES_reg(context),
- EFL_reg(context) );
+ BOOL bSetDOSExtendedError = FALSE;
+
+
+ TRACE("AX=%04x BX=%04x CX=%04x DX=%04x "
+ "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08lx\n",
+ AX_reg(context), BX_reg(context), CX_reg(context), DX_reg(context),
+ SI_reg(context), DI_reg(context),
+ (WORD)context->SegDs, (WORD)context->SegEs,
+ context->EFlags );
+
if (AH_reg(context) == 0x59) /* Get extended error info */
{
- AX_reg(context) = DOS_ExtendedError;
- BH_reg(context) = DOS_ErrorClass;
- BL_reg(context) = DOS_ErrorAction;
- CH_reg(context) = DOS_ErrorLocus;
+ INT21_GetExtendedError( context );
return;
}
- DOS_ERROR( 0, 0, 0, 0 );
+ if (AH_reg(context) == 0x0C) /* Flush buffer and read standard input */
+ {
+ TRACE("FLUSH BUFFER AND READ STANDARD INPUT\n");
+ /* no flush here yet */
+ AH_reg(context) = AL_reg(context);
+ }
+
+ if (AH_reg(context)>=0x2f) {
+ /* extended error is used by (at least) functions 0x2f to 0x62 */
+ SetLastError(0);
+ }
RESET_CFLAG(context); /* Not sure if this is a good idea */
- switch(AH_reg(context))
+ switch(AH_reg(context))
{
- case 0x00: /* TERMINATE PROGRAM */
- TASK_KillCurrentTask( 0 );
- break;
-
case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
case 0x03: /* READ CHARACTER FROM STDAUX */
case 0x04: /* WRITE CHARACTER TO STDAUX */
case 0x05: /* WRITE CHARACTER TO PRINTER */
case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
- case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
+ case 0x07: /* DIRECT CHARACTER INPUT WITHOUT ECHO */
case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
- case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
- case 0x0a: /* BUFFERED INPUT */
case 0x0b: /* GET STDIN STATUS */
- case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
case 0x0f: /* OPEN FILE USING FCB */
case 0x10: /* CLOSE FILE USING FCB */
- case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
+ case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */
case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */
case 0x21: /* READ RANDOM RECORD FROM FCB FILE */
case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */
case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */
case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */
- case 0x29: /* PARSE FILENAME INTO FCB */
- case 0x2e: /* SET VERIFY FLAG */
- case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER
- "SWITCHAR" - SET SWITCH CHARACTER
- "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
- case 0x54: /* GET VERIFY FLAG */
+ case 0x4d: /* GET RETURN CODE */
+ case 0x50: /* SET CURRENT PROCESS ID (SET PSP ADDRESS) */
INT_BARF( context, 0x21 );
break;
+ case 0x00: /* TERMINATE PROGRAM */
+ TRACE("TERMINATE PROGRAM\n");
+ ExitThread( 0 );
+ break;
+
+ case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
+ TRACE("WRITE '$'-terminated string from %04lX:%04X to stdout\n",
+ context->SegDs,DX_reg(context) );
+ {
+ LPSTR data = CTX_SEG_OFF_TO_LIN(context,context->SegDs,context->Edx);
+ LPSTR p = data;
+ /* do NOT use strchr() to calculate the string length,
+ as '\0' is valid string content, too !
+ Maybe we should check for non-'$' strings, but DOS doesn't. */
+ while (*p != '$') p++;
+ _hwrite16( 1, data, (int)p - (int)data);
+ AL_reg(context) = '$'; /* yes, '$' (0x24) gets returned in AL */
+ }
+ break;
+
+ case 0x0a: /* BUFFERED INPUT */
+ {
+ char *buffer = ((char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx ));
+ int res;
+
+ TRACE("BUFFERED INPUT (size=%d)\n",buffer[0]);
+ if (buffer[1])
+ TRACE("Handle old chars in buffer!\n");
+ res=_lread16( 0, buffer+2,buffer[0]);
+ buffer[1]=res;
+ if(buffer[res+1] == '\n')
+ buffer[res+1] = '\r';
+ break;
+ }
+
+ case 0x2e: /* SET VERIFY FLAG */
+ TRACE("SET VERIFY FLAG ignored\n");
+ /* we cannot change the behaviour anyway, so just ignore it */
+ break;
+
case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */
case 0x1d:
case 0x1e:
case 0x6b: /* NULL FUNCTION */
AL_reg(context) = 0;
break;
-
+
case 0x5c: /* "FLOCK" - RECORD LOCKING */
fLock(context);
break;
case 0x0d: /* DISK BUFFER FLUSH */
+ TRACE("DISK BUFFER FLUSH ignored\n");
RESET_CFLAG(context); /* dos 6+ only */
break;
case 0x0e: /* SELECT DEFAULT DRIVE */
+ TRACE("SELECT DEFAULT DRIVE %d\n", DL_reg(context));
DRIVE_SetCurrentDrive( DL_reg(context) );
AL_reg(context) = MAX_DOS_DRIVES;
break;
case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
+ TRACE("FIND FIRST MATCHING FILE USING FCB %p\n",
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
if (!INT21_FindFirstFCB(context))
{
AL_reg(context) = 0xff;
case 0x13: /* DELETE FILE USING FCB */
DeleteFileFCB(context);
break;
-
+
case 0x17: /* RENAME FILE USING FCB */
RenameFileFCB(context);
break;
case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
{
- TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
- pTask->dta = PTR_SEG_OFF_TO_SEGPTR(DS_reg(context),DX_reg(context));
- dprintf_int(stddeb, "int21: Set DTA: %08lx\n", pTask->dta);
+ TDB *pTask = TASK_GetCurrent();
+ pTask->dta = MAKESEGPTR(context->SegDs,DX_reg(context));
+ TRACE("Set DTA: %08lx\n", pTask->dta);
}
break;
DL_reg(context) = 0;
if (!INT21_GetDriveAllocInfo(context)) AX_reg(context) = 0xffff;
break;
-
+
case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */
if (!INT21_GetDriveAllocInfo(context)) AX_reg(context) = 0xffff;
break;
case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
GetDrivePB(context, DRIVE_GetCurrentDrive());
break;
-
+
case 0x25: /* SET INTERRUPT VECTOR */
- INT_SetHandler( AL_reg(context),
- (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( DS_reg(context),
- DX_reg(context)));
+ INT_SetPMHandler( AL_reg(context), (FARPROC16)MAKESEGPTR( context->SegDs, DX_reg(context)));
+ break;
+
+ case 0x29: /* PARSE FILENAME INTO FCB */
+ INT21_ParseFileNameIntoFCB(context);
break;
case 0x2a: /* GET SYSTEM DATE */
- GetSystemDate(context);
+ INT21_GetSystemDate(context);
break;
case 0x2b: /* SET SYSTEM DATE */
- fprintf( stdnimp, "SetSystemDate(%02d/%02d/%04d): not allowed\n",
- DL_reg(context), DH_reg(context), CX_reg(context) );
+ FIXME("SetSystemDate(%02d/%02d/%04d): not allowed\n",
+ DL_reg(context), DH_reg(context), CX_reg(context) );
AL_reg(context) = 0; /* Let's pretend we succeeded */
break;
break;
case 0x2d: /* SET SYSTEM TIME */
- fprintf( stdnimp, "SetSystemTime(%02d:%02d:%02d.%02d): not allowed\n",
- CH_reg(context), CL_reg(context),
- DH_reg(context), DL_reg(context) );
+ FIXME("SetSystemTime(%02d:%02d:%02d.%02d): not allowed\n",
+ CH_reg(context), CL_reg(context),
+ DH_reg(context), DL_reg(context) );
AL_reg(context) = 0; /* Let's pretend we succeeded */
break;
case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
+ TRACE("GET DISK TRANSFER AREA ADDRESS\n");
{
- TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
- ES_reg(context) = SELECTOROF( pTask->dta );
+ TDB *pTask = TASK_GetCurrent();
+ context->SegEs = SELECTOROF( pTask->dta );
BX_reg(context) = OFFSETOF( pTask->dta );
}
break;
-
+
case 0x30: /* GET DOS VERSION */
- AX_reg(context) = DOSVERSION;
- BX_reg(context) = 0x0012; /* 0x123456 is Wine's serial # */
- CX_reg(context) = 0x3456;
+ TRACE("GET DOS VERSION %s requested\n",
+ (AL_reg(context) == 0x00)?"OEM number":"version flag");
+ AX_reg(context) = (HIWORD(GetVersion16()) >> 8) |
+ (HIWORD(GetVersion16()) << 8);
+#if 0
+ AH_reg(context) = 0x7;
+ AL_reg(context) = 0xA;
+#endif
+
+ BX_reg(context) = 0x00FF; /* 0x123456 is Wine's serial # */
+ CX_reg(context) = 0x0000;
break;
case 0x31: /* TERMINATE AND STAY RESIDENT */
- INT_BARF( context, 0x21 );
+ FIXME("TERMINATE AND STAY RESIDENT stub\n");
break;
case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
+ TRACE("GET DOS DRIVE PARAMETER BLOCK FOR DRIVE %s\n",
+ INT21_DriveName( DL_reg(context)));
GetDrivePB(context, DOS_GET_DRIVE( DL_reg(context) ) );
break;
switch (AL_reg(context))
{
case 0x00: /* GET CURRENT EXTENDED BREAK STATE */
- DL_reg(context) = 0;
+ TRACE("GET CURRENT EXTENDED BREAK STATE\n");
+ INT21_ReadConfigSys();
+ DL_reg(context) = DOSCONF_config.brk_flag;
break;
case 0x01: /* SET EXTENDED BREAK STATE */
- break;
-
+ TRACE("SET CURRENT EXTENDED BREAK STATE\n");
+ INT21_ReadConfigSys();
+ DOSCONF_config.brk_flag = (DL_reg(context) > 0);
+ break;
+
case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE*/
- DL_reg(context) = 0;
+ TRACE("GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE\n");
+ INT21_ReadConfigSys();
+ /* ugly coding in order to stay reentrant */
+ if (DL_reg(context))
+ {
+ DL_reg(context) = DOSCONF_config.brk_flag;
+ DOSCONF_config.brk_flag = 1;
+ }
+ else
+ {
+ DL_reg(context) = DOSCONF_config.brk_flag;
+ DOSCONF_config.brk_flag = 0;
+ }
break;
case 0x05: /* GET BOOT DRIVE */
- DL_reg(context) = 2;
- /* c: is Wine's bootdrive */
+ TRACE("GET BOOT DRIVE\n");
+ DL_reg(context) = 3;
+ /* c: is Wine's bootdrive (a: is 1)*/
break;
-
+
case 0x06: /* GET TRUE VERSION NUMBER */
- BX_reg(context) = DOSVERSION;
+ TRACE("GET TRUE VERSION NUMBER\n");
+ BX_reg(context) = (HIWORD(GetVersion16() >> 8)) |
+ (HIWORD(GetVersion16() << 8));
DX_reg(context) = 0x00;
break;
default:
INT_BARF( context, 0x21 );
- break;
+ break;
}
- break;
-
+ break;
+
case 0x34: /* GET ADDRESS OF INDOS FLAG */
+ TRACE("GET ADDRESS OF INDOS FLAG\n");
if (!heap) INT21_CreateHeap();
- ES_reg(context) = DosHeapHandle;
+ context->SegEs = DosHeapHandle;
BX_reg(context) = (int)&heap->InDosFlag - (int)heap;
break;
case 0x35: /* GET INTERRUPT VECTOR */
+ TRACE("GET INTERRUPT VECTOR 0x%02x\n",AL_reg(context));
{
- FARPROC16 addr = INT_GetHandler( AL_reg(context) );
- ES_reg(context) = SELECTOROF(addr);
+ FARPROC16 addr = INT_GetPMHandler( AL_reg(context) );
+ context->SegEs = SELECTOROF(addr);
BX_reg(context) = OFFSETOF(addr);
}
break;
case 0x36: /* GET FREE DISK SPACE */
+ TRACE("GET FREE DISK SPACE FOR DRIVE %s\n",
+ INT21_DriveName( DL_reg(context)));
if (!INT21_GetFreeDiskSpace(context)) AX_reg(context) = 0xffff;
break;
+ case 0x37:
+ {
+ unsigned char switchchar='/';
+ switch (AL_reg(context))
+ {
+ case 0x00: /* "SWITCHAR" - GET SWITCH CHARACTER */
+ TRACE("SWITCHAR - GET SWITCH CHARACTER\n");
+ AL_reg(context) = 0x00; /* success*/
+ DL_reg(context) = switchchar;
+ break;
+ case 0x01: /*"SWITCHAR" - SET SWITCH CHARACTER*/
+ TRACE("SWITCHAR - SET SWITCH CHARACTER\n");
+ switchchar = DL_reg(context);
+ AL_reg(context) = 0x00; /* success*/
+ break;
+ default: /*"AVAILDEV" - SPECIFY \DEV\ PREFIX USE*/
+ INT_BARF( context, 0x21 );
+ break;
+ }
+ break;
+ }
+
case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
+ TRACE("GET COUNTRY-SPECIFIC INFORMATION for country 0x%02x\n",
+ AL_reg(context));
AX_reg(context) = 0x02; /* no country support available */
SET_CFLAG(context);
break;
case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
- if (!CreateDirectory16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) ), NULL))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("MKDIR %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError = (!CreateDirectory16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx ), NULL));
+ /* FIXME: CreateDirectory's LastErrors will clash with the ones
+ * used by dos. AH=39 only returns 3 (path not found) and 5 (access
+ * denied), while CreateDirectory return several ones. remap some of
+ * them. -Marcus
+ */
+ if (bSetDOSExtendedError) {
+ switch (GetLastError()) {
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILENAME_EXCED_RANGE:
+ case ERROR_DISK_FULL:
+ SetLastError(ERROR_ACCESS_DENIED);
+ break;
+ default: break;
+ }
+ }
break;
-
+
case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
- if (!RemoveDirectory16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) )))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("RMDIR %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError = (!RemoveDirectory16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx )));
break;
case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
- INT21_ChangeDir(context);
+ TRACE("CHDIR %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError = !INT21_ChangeDir(context);
break;
-
+
case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
- AX_reg(context) = _lcreat16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) ), CX_reg(context) );
- if (AX_reg(context) == (WORD)HFILE_ERROR16)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("CREAT flag 0x%02x %s\n",CX_reg(context),
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError = INT21_CreateFile( context );
break;
case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
+ TRACE("OPEN mode 0x%02x %s\n",AL_reg(context),
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
OpenExistingFile(context);
break;
case 0x3e: /* "CLOSE" - CLOSE FILE */
- if ((AX_reg(context) = _lclose16( BX_reg(context) )) != 0)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("CLOSE handle %d\n",BX_reg(context));
+ bSetDOSExtendedError = ((AX_reg(context) = _lclose16( BX_reg(context) )) != 0);
break;
case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
+ TRACE("READ from %d to %04lX:%04X for %d byte\n",BX_reg(context),
+ context->SegDs,DX_reg(context),CX_reg(context) );
{
- LONG result = WIN16_hread( BX_reg(context),
- PTR_SEG_OFF_TO_SEGPTR( DS_reg(context),
- DX_reg(context) ),
- CX_reg(context) );
- if (result == -1)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ LONG result;
+ if (ISV86(context))
+ result = _hread16( BX_reg(context),
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx ),
+ CX_reg(context) );
+ else
+ result = WIN16_hread( BX_reg(context),
+ MAKESEGPTR( context->SegDs, context->Edx ),
+ CX_reg(context) );
+ if (result == -1) bSetDOSExtendedError = TRUE;
else AX_reg(context) = (WORD)result;
}
break;
case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
+ TRACE("WRITE from %04lX:%04X to handle %d for %d byte\n",
+ context->SegDs,DX_reg(context),BX_reg(context),CX_reg(context) );
{
LONG result = _hwrite16( BX_reg(context),
- PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) ),
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx ),
CX_reg(context) );
- if (result == -1)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ if (result == -1) bSetDOSExtendedError = TRUE;
else AX_reg(context) = (WORD)result;
}
break;
case 0x41: /* "UNLINK" - DELETE FILE */
- if (!DeleteFile32A( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) )))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("UNLINK %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError = (!DeleteFileA( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx )));
break;
case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
+ TRACE("LSEEK handle %d offset %ld from %s\n",
+ BX_reg(context), MAKELONG(DX_reg(context),CX_reg(context)),
+ (AL_reg(context)==0)?"start of file":(AL_reg(context)==1)?
+ "current file position":"end of file");
{
LONG status = _llseek16( BX_reg(context),
MAKELONG(DX_reg(context),CX_reg(context)),
AL_reg(context) );
- if (status == -1)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- break;
- }
- AX_reg(context) = LOWORD(status);
- DX_reg(context) = HIWORD(status);
+ if (status == -1) bSetDOSExtendedError = TRUE;
+ else
+ {
+ AX_reg(context) = LOWORD(status);
+ DX_reg(context) = HIWORD(status);
+ }
}
break;
switch (AL_reg(context))
{
case 0x00:
- if (!INT21_GetFileAttribute(context))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("GET FILE ATTRIBUTES for %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ AX_reg(context) = (WORD)GetFileAttributesA(
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx));
+ if (AX_reg(context) == 0xffff) bSetDOSExtendedError = TRUE;
+ else CX_reg(context) = AX_reg(context);
break;
+
case 0x01:
- RESET_CFLAG(context);
+ TRACE("SET FILE ATTRIBUTES 0x%02x for %s\n", CX_reg(context),
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError =
+ (!SetFileAttributesA( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx),
+ CX_reg(context) ));
break;
+ case 0x02:
+ FIXME("GET COMPRESSED FILE SIZE for %s stub\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
}
break;
-
+
case 0x44: /* IOCTL */
switch (AL_reg(context))
{
case 0x01:
break;
+ case 0x02:{
+ const DOS_DEVICE *dev;
+ if ((dev = DOSFS_GetDeviceByHandle( DosFileHandleToWin32Handle(BX_reg(context)) )) &&
+ !strcasecmp( dev->name, "SCSIMGR$" ))
+ {
+ ASPI_DOS_HandleInt(context);
+ }
+ break;
+ }
case 0x05:{ /* IOCTL - WRITE TO BLOCK DEVICE CONTROL CHANNEL */
- BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context));
- int i;
+ /*BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx);*/
int drive = DOS_GET_DRIVE(BL_reg(context));
- fprintf(stdnimp,"int21: program tried to write to block device control channel of drive %d:\n",drive);
- for (i=0;i<CX_reg(context);i++)
+ FIXME("program tried to write to block device control channel of drive %d:\n",drive);
+ /* for (i=0;i<CX_reg(context);i++)
fprintf(stdnimp,"%02x ",dataptr[i]);
- fprintf(stdnimp,"\n");
+ fprintf(stdnimp,"\n");*/
AX_reg(context)=CX_reg(context);
break;
}
case 0x08: /* Check if drive is removable. */
+ TRACE("IOCTL - CHECK IF BLOCK DEVICE REMOVABLE for drive %s\n",
+ INT21_DriveName( BL_reg(context)));
switch(GetDriveType16( DOS_GET_DRIVE( BL_reg(context) )))
{
- case DRIVE_CANNOTDETERMINE:
- DOS_ERROR( ER_InvalidDrive, EC_NotFound, SA_Abort, EL_Disk );
- AX_reg(context) = ER_InvalidDrive;
+ case DRIVE_UNKNOWN:
+ SetLastError( ERROR_INVALID_DRIVE );
+ AX_reg(context) = ERROR_INVALID_DRIVE;
SET_CFLAG(context);
break;
case DRIVE_REMOVABLE:
break;
case 0x09: /* CHECK IF BLOCK DEVICE REMOTE */
+ TRACE("IOCTL - CHECK IF BLOCK DEVICE REMOTE for drive %s\n",
+ INT21_DriveName( BL_reg(context)));
switch(GetDriveType16( DOS_GET_DRIVE( BL_reg(context) )))
{
- case DRIVE_CANNOTDETERMINE:
- DOS_ERROR( ER_InvalidDrive, EC_NotFound, SA_Abort, EL_Disk );
- AX_reg(context) = ER_InvalidDrive;
+ case DRIVE_UNKNOWN:
+ SetLastError( ERROR_INVALID_DRIVE );
+ AX_reg(context) = ERROR_INVALID_DRIVE;
SET_CFLAG(context);
break;
case DRIVE_REMOTE:
break;
case 0x0a: /* check if handle (BX) is remote */
+ TRACE("IOCTL - CHECK IF HANDLE %d IS REMOTE\n",BX_reg(context));
/* returns DX, bit 15 set if remote, bit 14 set if date/time
* not set on close
*/
DX_reg(context) = 0;
break;
- case 0x0b: /* SET SHARING RETRY COUNT */
- if (!CX_reg(context))
- {
- AX_reg(context) = 1;
- SET_CFLAG(context);
- break;
- }
- sharing_pause = CX_reg(context);
- if (!DX_reg(context))
- sharing_retries = DX_reg(context);
- RESET_CFLAG(context);
- break;
-
case 0x0d:
- ioctlGenericBlkDevReq(context);
+ TRACE("IOCTL - GENERIC BLOCK DEVICE REQUEST %s\n",
+ INT21_DriveName( BL_reg(context)));
+ bSetDOSExtendedError = ioctlGenericBlkDevReq(context);
break;
+
case 0x0e: /* get logical drive mapping */
- AL_reg(context) = 0; /* drive has no mapping */
+ TRACE("IOCTL - GET LOGICAL DRIVE MAP for drive %s\n",
+ INT21_DriveName( BL_reg(context)));
+ AL_reg(context) = 0; /* drive has no mapping - FIXME: may be wrong*/
break;
case 0x0F: /* Set logical drive mapping */
- /* FIXME: Not implemented at the moment, always returns error
- */
- INT_BARF( context, 0x21 );
- AX_reg(context) = 0x0001; /* invalid function */
- SET_CFLAG(context);
+ {
+ int drive;
+ TRACE("IOCTL - SET LOGICAL DRIVE MAP for drive %s\n",
+ INT21_DriveName( BL_reg(context)));
+ drive = DOS_GET_DRIVE ( BL_reg(context) );
+ if ( ! DRIVE_SetLogicalMapping ( drive, drive+1 ) )
+ {
+ SET_CFLAG(context);
+ AX_reg(context) = 0x000F; /* invalid drive */
+ }
+ break;
+ }
+
+ case 0xe0: /* Sun PC-NFS API */
+ /* not installed */
break;
-
+
+ case 0x52: /* DR-DOS version */
+ /* This is not DR-DOS */
+
+ TRACE("GET DR-DOS VERSION requested\n");
+
+ AX_reg(context) = 0x0001; /* Invalid function */
+ SET_CFLAG(context); /* Error */
+ SetLastError( ERROR_INVALID_FUNCTION );
+ break;
+
default:
INT_BARF( context, 0x21 );
break;
break;
case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
- if ((AX_reg(context) = FILE_Dup(BX_reg(context))) == (WORD)HFILE_ERROR16)
{
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
+ HANDLE handle;
+ TRACE("DUP - DUPLICATE FILE HANDLE %d\n",BX_reg(context));
+ if ((bSetDOSExtendedError = !DuplicateHandle( GetCurrentProcess(),
+ DosFileHandleToWin32Handle(BX_reg(context)),
+ GetCurrentProcess(), &handle,
+ 0, TRUE, DUPLICATE_SAME_ACCESS )))
+ AX_reg(context) = HFILE_ERROR16;
+ else
+ AX_reg(context) = Win32HandleToDosFileHandle(handle);
+ break;
}
- break;
case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
- if (FILE_Dup2( BX_reg(context), CX_reg(context) ) == HFILE_ERROR32)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("FORCEDUP - FORCE DUPLICATE FILE HANDLE %d to %d\n",
+ BX_reg(context),CX_reg(context));
+ bSetDOSExtendedError = (FILE_Dup2( BX_reg(context), CX_reg(context) ) == HFILE_ERROR16);
break;
case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
- if (!INT21_GetCurrentDirectory(context))
+ TRACE("CWD - GET CURRENT DIRECTORY for drive %s\n",
+ INT21_DriveName( DL_reg(context)));
+ bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
+ break;
+
+ case 0x48: /* ALLOCATE MEMORY */
+ TRACE("ALLOCATE MEMORY for %d paragraphs\n", BX_reg(context));
+ {
+ LPVOID *mem;
+ if (ISV86(context))
+ {
+ mem= DOSMEM_GetBlock((DWORD)BX_reg(context)<<4,NULL);
+ if (mem)
+ AX_reg(context) = DOSMEM_MapLinearToDos(mem)>>4;
+ }
+ else
+ {
+ mem = (LPVOID)GlobalDOSAlloc16(BX_reg(context)<<4);
+ if (mem)
+ AX_reg(context) = (DWORD)mem&0xffff;
+ }
+ if (!mem)
+ {
+ SET_CFLAG(context);
+ AX_reg(context) = 0x0008; /* insufficient memory */
+ BX_reg(context) = DOSMEM_Available()>>4;
+ }
+ }
+ break;
+
+ case 0x49: /* FREE MEMORY */
+ TRACE("FREE MEMORY segment %04lX\n", context->SegEs);
{
- AX_reg(context) = DOS_ExtendedError;
+ BOOL ret;
+ if (ISV86(context))
+ ret= DOSMEM_FreeBlock(DOSMEM_MapDosToLinear(context->SegEs<<4));
+ else
+ {
+ ret = !GlobalDOSFree16(context->SegEs);
+ /* If we don't reset ES_reg, we will fail in the relay code */
+ context->SegEs=ret;
+ }
+ if (!ret)
+ {
+ TRACE("FREE MEMORY failed\n");
SET_CFLAG(context);
+ AX_reg(context) = 0x0009; /* memory block address invalid */
}
- else AX_reg(context) = 0x0100;
- /* intlist: many Microsoft products for Windows rely on this */
+ }
break;
-
- case 0x48: /* ALLOCATE MEMORY */
- case 0x49: /* FREE MEMORY */
+
case 0x4a: /* RESIZE MEMORY BLOCK */
- INT_BARF( context, 0x21 );
+ TRACE("RESIZE MEMORY segment %04lX to %d paragraphs\n", context->SegEs, BX_reg(context));
+ if (!ISV86(context))
+ FIXME("RESIZE MEMORY probably insufficient implementation. Expect crash soon\n");
+ {
+ LPVOID *mem = DOSMEM_ResizeBlock(DOSMEM_MapDosToLinear(context->SegEs<<4),
+ BX_reg(context)<<4,NULL);
+ if (mem)
+ AX_reg(context) = DOSMEM_MapLinearToDos(mem)>>4;
+ else {
+ SET_CFLAG(context);
+ AX_reg(context) = 0x0008; /* insufficient memory */
+ BX_reg(context) = DOSMEM_Available()>>4; /* not quite right */
+ }
+ }
break;
-
+
case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
- AX_reg(context) = WinExec16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) ),
+ TRACE("EXEC %s\n", (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx ));
+ AX_reg(context) = WinExec16( CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx ),
SW_NORMAL );
if (AX_reg(context) < 32) SET_CFLAG(context);
- break;
-
- case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
- TASK_KillCurrentTask( AL_reg(context) );
break;
- case 0x4d: /* GET RETURN CODE */
- AX_reg(context) = 0; /* normal exit */
+ case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
+ TRACE("EXIT with return code %d\n",AL_reg(context));
+ ExitThread( AL_reg(context) );
break;
case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
+ TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
if (!INT21_FindFirst(context)) break;
/* fall through */
case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
+ TRACE("FINDNEXT\n");
if (!INT21_FindNext(context))
{
- DOS_ERROR( ER_NoMoreFiles, EC_MediaError, SA_Abort, EL_Disk );
- AX_reg(context) = ER_NoMoreFiles;
+ SetLastError( ERROR_NO_MORE_FILES );
+ AX_reg(context) = ERROR_NO_MORE_FILES;
SET_CFLAG(context);
}
+ else AX_reg(context) = 0; /* OK */
break;
-
case 0x51: /* GET PSP ADDRESS */
+ TRACE("GET CURRENT PROCESS ID (GET PSP ADDRESS)\n");
+ /* FIXME: should we return the original DOS PSP upon */
+ /* Windows startup ? */
+ BX_reg(context) = GetCurrentPDB16();
+ break;
case 0x62: /* GET PSP ADDRESS */
/* FIXME: should we return the original DOS PSP upon */
/* Windows startup ? */
- BX_reg(context) = GetCurrentPDB();
+ BX_reg(context) = GetCurrentPDB16();
break;
case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
- ES_reg(context) = 0x0;
- BX_reg(context) = 0x0;
- INT_BARF( context, 0x21 );
+ TRACE("SYSVARS - GET LIST OF LISTS\n");
+ {
+ context->SegEs = LOWORD(DOS_LOLSeg);
+ BX_reg(context) = FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB);
+ }
break;
+ case 0x54: /* Get Verify Flag */
+ TRACE("Get Verify Flag - Not Supported\n");
+ AL_reg(context) = 0x00; /* pretend we can tell. 00h = off 01h = on */
+ break;
+
case 0x56: /* "RENAME" - RENAME FILE */
- if (!INT21_RenameFile(context))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("RENAME %s to %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegEs,context->Edi));
+ bSetDOSExtendedError =
+ (!MoveFileA( CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
+ CTX_SEG_OFF_TO_LIN(context, context->SegEs,context->Edi)));
break;
case 0x57: /* FILE DATE AND TIME */
case 0x00: /* Get */
{
FILETIME filetime;
- if (!GetFileTime( BX_reg(context), NULL, NULL, &filetime ))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("GET FILE DATE AND TIME for handle %d\n",
+ BX_reg(context));
+ if (!GetFileTime( DosFileHandleToWin32Handle(BX_reg(context)), NULL, NULL, &filetime ))
+ bSetDOSExtendedError = TRUE;
else FileTimeToDosDateTime( &filetime, &DX_reg(context),
&CX_reg(context) );
}
case 0x01: /* Set */
{
FILETIME filetime;
+ TRACE("SET FILE DATE AND TIME for handle %d\n",
+ BX_reg(context));
DosDateTimeToFileTime( DX_reg(context), CX_reg(context),
&filetime );
- if (!SetFileTime( BX_reg(context), NULL, NULL, &filetime ))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ bSetDOSExtendedError =
+ (!SetFileTime( DosFileHandleToWin32Handle(BX_reg(context)),
+ NULL, NULL, &filetime ));
}
break;
}
break;
case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */
+ TRACE("GET OR SET MEMORY/UMB ALLOCATION STRATEGY subfunction %d\n",
+ AL_reg(context));
switch (AL_reg(context))
{
case 0x00:
break;
case 0x5a: /* CREATE TEMPORARY FILE */
- if (!INT21_CreateTempFile(context))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("CREATE TEMPORARY FILE\n");
+ bSetDOSExtendedError = !INT21_CreateTempFile(context);
break;
case 0x5b: /* CREATE NEW FILE */
- if ((AX_reg(context) = _lcreat_uniq( PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)), 0 )) == (WORD)HFILE_ERROR16)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("CREATE NEW FILE 0x%02x for %s\n", CX_reg(context),
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ bSetDOSExtendedError = ((AX_reg(context) =
+ _lcreat16_uniq( CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
+ CX_reg(context) )) == (WORD)HFILE_ERROR16);
break;
case 0x5d: /* NETWORK */
+ FIXME("Function 0x%04x not implemented.\n", AX_reg (context));
+ /* Fix the following while you're at it. */
+ SetLastError( ER_NoNetwork );
+ bSetDOSExtendedError = TRUE;
+ break;
+
case 0x5e:
- /* network software not installed */
- DOS_ERROR( ER_NoNetwork, EC_NotFound, SA_Abort, EL_Network );
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
+ bSetDOSExtendedError = INT21_networkfunc (context);
break;
case 0x5f: /* NETWORK */
switch (AL_reg(context))
{
case 0x07: /* ENABLE DRIVE */
+ TRACE("ENABLE DRIVE %c:\n",(DL_reg(context)+'A'));
if (!DRIVE_Enable( DL_reg(context) ))
{
- DOS_ERROR( ER_InvalidDrive, EC_MediaError, SA_Abort, EL_Disk );
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
+ SetLastError( ERROR_INVALID_DRIVE );
+ bSetDOSExtendedError = TRUE;
}
break;
case 0x08: /* DISABLE DRIVE */
+ TRACE("DISABLE DRIVE %c:\n",(DL_reg(context)+'A'));
if (!DRIVE_Disable( DL_reg(context) ))
{
- DOS_ERROR( ER_InvalidDrive, EC_MediaError, SA_Abort, EL_Disk );
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ SetLastError( ERROR_INVALID_DRIVE );
+ bSetDOSExtendedError = TRUE;
+ }
break;
default:
/* network software not installed */
- DOS_ERROR( ER_NoNetwork, EC_NotFound, SA_Abort, EL_Network );
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
+ TRACE("NETWORK function AX=%04x not implemented\n",AX_reg(context));
+ SetLastError( ER_NoNetwork );
+ bSetDOSExtendedError = TRUE;
break;
}
break;
case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
+ TRACE("TRUENAME %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Esi));
{
- const char *truename = DOSFS_GetDosTrueName( PTR_SEG_OFF_TO_LIN(DS_reg(context),SI_reg(context) ), FALSE );
- if (!truename)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
- else
- {
- lstrcpyn32A( PTR_SEG_OFF_TO_LIN( ES_reg(context),
- DI_reg(context) ),
- truename, 128 );
- AX_reg(context) = 0;
- }
+ if (!GetFullPathNameA( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Esi), 128,
+ CTX_SEG_OFF_TO_LIN(context, context->SegEs,
+ context->Edi),NULL))
+ bSetDOSExtendedError = TRUE;
+ else AX_reg(context) = 0;
}
break;
case 0x61: /* UNUSED */
- case 0x63: /* UNUSED */
+ case 0x63: /* misc. language support */
+ switch (AL_reg(context)) {
+ case 0x00: /* GET DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */
+ INT21_GetDBCSLeadTable(context);
+ break;
+ }
+ break;
case 0x64: /* OS/2 DOS BOX */
INT_BARF( context, 0x21 );
SET_CFLAG(context);
break;
+
case 0x65:{/* GET EXTENDED COUNTRY INFORMATION */
- extern WORD WINE_LanguageId;
- BYTE *dataptr=PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context));;
+ BYTE *dataptr=CTX_SEG_OFF_TO_LIN(context, context->SegEs,context->Edi);
+ TRACE("GET EXTENDED COUNTRY INFORMATION code page %d country %d\n",
+ BX_reg(context), DX_reg(context));
switch (AL_reg(context)) {
case 0x01:
+ TRACE("\tget general internationalization info\n");
dataptr[0] = 0x1;
*(WORD*)(dataptr+1) = 41;
- *(WORD*)(dataptr+3) = WINE_LanguageId;
+ *(WORD*)(dataptr+3) = GetSystemDefaultLangID();
*(WORD*)(dataptr+5) = CodePage;
+ *(DWORD*)(dataptr+0x19) = 0; /* FIXME: ptr to case map routine */
break;
case 0x06:
+ TRACE("\tget pointer to collating sequence table\n");
dataptr[0] = 0x06;
*(DWORD*)(dataptr+1) = MAKELONG(DOSMEM_CollateTable & 0xFFFF,DOSMEM_AllocSelector(DOSMEM_CollateTable>>16));
CX_reg(context) = 258;/*FIXME: size of table?*/
break;
+ case 0x20:
+ TRACE("\tConvert char to uppercase\n");
+ DL_reg(context) = toupper(DL_reg(context));
+ break;
+ case 0x21:
+ TRACE("\tconvert string to uppercase with length\n");
+ {
+ char *ptr = (char *)CTX_SEG_OFF_TO_LIN(context,context->SegDs,context->Edx);
+ WORD len = CX_reg(context);
+ while (len--) { *ptr = toupper(*ptr); ptr++; }
+ }
+ break;
+ case 0x22:
+ TRACE("\tConvert ASCIIZ string to uppercase\n");
+ _strupr( (LPSTR)CTX_SEG_OFF_TO_LIN(context,context->SegDs,context->Edx) );
+ break;
default:
+ TRACE("\tunimplemented function %d\n",AL_reg(context));
INT_BARF( context, 0x21 );
SET_CFLAG(context);
break;
switch (AL_reg(context))
{
case 0x01:
+ TRACE("GET GLOBAL CODE PAGE TABLE\n");
DX_reg(context) = BX_reg(context) = CodePage;
RESET_CFLAG(context);
- break;
- case 0x02:
+ break;
+ case 0x02:
+ TRACE("SET GLOBAL CODE PAGE TABLE active page %d system page %d\n",
+ BX_reg(context),DX_reg(context));
CodePage = BX_reg(context);
RESET_CFLAG(context);
break;
break;
case 0x67: /* SET HANDLE COUNT */
+ TRACE("SET HANDLE COUNT to %d\n",BX_reg(context) );
SetHandleCount16( BX_reg(context) );
- if (DOS_ExtendedError)
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ if (GetLastError()) bSetDOSExtendedError = TRUE;
break;
case 0x68: /* "FFLUSH" - COMMIT FILE */
case 0x6a: /* COMMIT FILE */
- if (!FlushFileBuffers( BX_reg(context) ))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
- break;
-
+ TRACE("FFLUSH/COMMIT handle %d\n",BX_reg(context));
+ bSetDOSExtendedError = (!FlushFileBuffers( DosFileHandleToWin32Handle(BX_reg(context)) ));
+ break;
+
case 0x69: /* DISK SERIAL NUMBER */
switch (AL_reg(context))
{
case 0x00:
- if (!INT21_GetDiskSerialNumber(context))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("GET DISK SERIAL NUMBER for drive %s\n",
+ INT21_DriveName(BL_reg(context)));
+ if (!INT21_GetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE;
else AX_reg(context) = 0;
break;
+
case 0x01:
- if (!INT21_SetDiskSerialNumber(context))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("SET DISK SERIAL NUMBER for drive %s\n",
+ INT21_DriveName(BL_reg(context)));
+ if (!INT21_SetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE;
else AX_reg(context) = 1;
break;
}
break;
-
+
case 0x6C: /* Extended Open/Create*/
- ExtendedOpenCreateFile(context);
+ TRACE("EXTENDED OPEN/CREATE %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edi));
+ bSetDOSExtendedError = INT21_ExtendedOpenCreateFile(context);
break;
-
+
case 0x71: /* MS-DOS 7 (Windows95) - LONG FILENAME FUNCTIONS */
+ if ((GetVersion()&0xC0000004)!=0xC0000004) {
+ /* not supported on anything but Win95 */
+ TRACE("LONG FILENAME functions supported only by win95\n");
+ SET_CFLAG(context);
+ AL_reg(context) = 0;
+ } else
switch(AL_reg(context))
{
case 0x39: /* Create directory */
- if (!CreateDirectory32A( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) ), NULL))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("LONG FILENAME - MAKE DIRECTORY %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx));
+ bSetDOSExtendedError = (!CreateDirectoryA(
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx ), NULL));
+ /* FIXME: CreateDirectory's LastErrors will clash with the ones
+ * used by dos. AH=39 only returns 3 (path not found) and 5 (access
+ * denied), while CreateDirectory return several ones. remap some of
+ * them. -Marcus
+ */
+ if (bSetDOSExtendedError) {
+ switch (GetLastError()) {
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILENAME_EXCED_RANGE:
+ case ERROR_DISK_FULL:
+ SetLastError(ERROR_ACCESS_DENIED);
+ break;
+ default: break;
+ }
+ }
break;
case 0x3a: /* Remove directory */
- if (!RemoveDirectory32A( PTR_SEG_OFF_TO_LIN( DS_reg(context),
- DX_reg(context) )))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("LONG FILENAME - REMOVE DIRECTORY %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx));
+ bSetDOSExtendedError = (!RemoveDirectoryA(
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx )));
+ break;
+ case 0x43: /* Get/Set file attributes */
+ TRACE("LONG FILENAME -EXTENDED GET/SET FILE ATTRIBUTES %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx));
+ switch (BL_reg(context))
+ {
+ case 0x00: /* Get file attributes */
+ TRACE("\tretrieve attributes\n");
+ CX_reg(context) = (WORD)GetFileAttributesA(
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx));
+ if (CX_reg(context) == 0xffff) bSetDOSExtendedError = TRUE;
+ break;
+ case 0x01:
+ TRACE("\tset attributes 0x%04x\n",CX_reg(context));
+ bSetDOSExtendedError = (!SetFileAttributesA(
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Edx),
+ CX_reg(context) ) );
+ break;
+ default:
+ FIXME("Unimplemented long file name function:\n");
+ INT_BARF( context, 0x21 );
+ SET_CFLAG(context);
+ AL_reg(context) = 0;
+ break;
+ }
+ break;
+ case 0x47: /* Get current directory */
+ TRACE(" LONG FILENAME - GET CURRENT DIRECTORY for drive %s\n",
+ INT21_DriveName(DL_reg(context)));
+ bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
break;
+
case 0x4e: /* Find first file */
+ TRACE(" LONG FILENAME - FIND FIRST MATCHING FILE for %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx));
/* FIXME: use attributes in CX */
- if (!(AX_reg(context) = FindFirstFile16(
- PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
- (WIN32_FIND_DATA32A *)PTR_SEG_OFF_TO_LIN(ES_reg(context),
- DI_reg(context)))))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ if ((AX_reg(context) = FindFirstFile16(
+ CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
+ (WIN32_FIND_DATAA *)CTX_SEG_OFF_TO_LIN(context, context->SegEs,
+ context->Edi)))
+ == INVALID_HANDLE_VALUE16)
+ bSetDOSExtendedError = TRUE;
break;
case 0x4f: /* Find next file */
+ TRACE("LONG FILENAME - FIND NEXT MATCHING FILE for handle %d\n",
+ BX_reg(context));
if (!FindNextFile16( BX_reg(context),
- (WIN32_FIND_DATA32A *)PTR_SEG_OFF_TO_LIN(ES_reg(context),
- DI_reg(context))))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ (WIN32_FIND_DATAA *)CTX_SEG_OFF_TO_LIN(context, context->SegEs,
+ context->Edi)))
+ bSetDOSExtendedError = TRUE;
break;
+ case 0xa0:
+ {
+ LPCSTR driveroot = (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx);
+ LPSTR buffer = (LPSTR)CTX_SEG_OFF_TO_LIN(context, context->SegEs,context->Edi);
+ DWORD filename_len, flags;
+
+ TRACE("LONG FILENAME - GET VOLUME INFORMATION for drive having root dir '%s'.\n", driveroot);
+ AX_reg(context) = 0;
+ if (!GetVolumeInformationA( driveroot, NULL, 0, NULL, &filename_len,
+ &flags, buffer, 8 ))
+ {
+ INT_BARF( context, 0x21 );
+ SET_CFLAG(context);
+ break;
+ }
+ BX_reg(context) = flags | 0x4000; /* support for LFN functions */
+ CX_reg(context) = filename_len;
+ DX_reg(context) = MAX_PATH; /* FIXME: which len if DRIVE_SHORT_NAMES ? */
+ }
+ break;
case 0xa1: /* Find close */
- if (!FindClose16( BX_reg(context) ))
- {
- AX_reg(context) = DOS_ExtendedError;
- SET_CFLAG(context);
- }
+ TRACE("LONG FILENAME - FINDCLOSE for handle %d\n",
+ BX_reg(context));
+ bSetDOSExtendedError = (!FindClose16( BX_reg(context) ));
break;
- case 0xa0:
+ case 0x60:
+ switch(CL_reg(context))
+ {
+ case 0x01: /* Get short filename or path */
+ if (!GetShortPathNameA
+ ( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Esi),
+ CTX_SEG_OFF_TO_LIN(context, context->SegEs,
+ context->Edi), 67))
+ bSetDOSExtendedError = TRUE;
+ else AX_reg(context) = 0;
+ break;
+ case 0x02: /* Get canonical long filename or path */
+ if (!GetFullPathNameA
+ ( CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+ context->Esi), 128,
+ CTX_SEG_OFF_TO_LIN(context, context->SegEs,
+ context->Edi),NULL))
+ bSetDOSExtendedError = TRUE;
+ else AX_reg(context) = 0;
+ break;
+ default:
+ FIXME("Unimplemented long file name function:\n");
+ INT_BARF( context, 0x21 );
+ SET_CFLAG(context);
+ AL_reg(context) = 0;
+ break;
+ }
+ break;
+ case 0x6c: /* Create or open file */
+ TRACE("LONG FILENAME - CREATE OR OPEN FILE %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi));
+ /* translate Dos 7 action to Dos 6 action */
+ bSetDOSExtendedError = INT21_ExtendedOpenCreateFile(context);
break;
+
case 0x3b: /* Change directory */
+ TRACE("LONG FILENAME - CHANGE DIRECTORY %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ if (!SetCurrentDirectoryA(CTX_SEG_OFF_TO_LIN(context,
+ context->SegDs,
+ context->Edx
+ ))
+ ) {
+ SET_CFLAG(context);
+ AL_reg(context) = GetLastError();
+ }
+ break;
case 0x41: /* Delete file */
- case 0x43: /* Get/Set file attributes */
- case 0x47: /* Get current directory */
+ TRACE("LONG FILENAME - DELETE FILE %s\n",
+ (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
+ if (!DeleteFileA(CTX_SEG_OFF_TO_LIN(context,
+ context->SegDs,
+ context->Edx)
+ )) {
+ SET_CFLAG(context);
+ AL_reg(context) = GetLastError();
+ }
+ break;
case 0x56: /* Move (rename) file */
- case 0x6c: /* Create/Open file */
+ {
+ LPCSTR fn1 = (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
+ LPCSTR fn2 = (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi);
+ TRACE("LONG FILENAME - RENAME FILE %s to %s\n", fn1, fn2);
+ if (!MoveFileA(fn1, fn2))
+ {
+ SET_CFLAG(context);
+ AL_reg(context) = GetLastError();
+ }
+ }
+ break;
default:
- fprintf( stderr, "Unimplemented int21 long file name function:\n");
+ FIXME("Unimplemented long file name function:\n");
INT_BARF( context, 0x21 );
SET_CFLAG(context);
AL_reg(context) = 0;
case 0x70: /* MS-DOS 7 (Windows95) - ??? (country-specific?)*/
case 0x72: /* MS-DOS 7 (Windows95) - ??? */
- case 0x73: /* MS-DOS 7 (Windows95) - DRIVE LOCKING ??? */
- dprintf_int(stddeb,"int21: windows95 function AX %04x\n",
+ TRACE("windows95 function AX %04x\n",
AX_reg(context));
- dprintf_int(stddeb, " returning unimplemented\n");
+ WARN(" returning unimplemented\n");
SET_CFLAG(context);
AL_reg(context) = 0;
break;
+ case 0x73: /* MULTIPLEXED: Win95 OSR2/Win98 FAT32 calls */
+ TRACE("windows95 function AX %04x\n",
+ AX_reg(context));
+
+ switch (AL_reg(context))
+ {
+ case 0x02: /* Get Extended Drive Parameter Block for specific drive */
+ /* ES:DI points to word with length of data (should be 0x3d) */
+ {
+ WORD *buffer;
+ struct EDPB *edpb;
+ DWORD cluster_sectors, sector_bytes, free_clusters, total_clusters;
+ char root[] = "A:\\";
+
+ buffer = (WORD *)CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi);
+
+ TRACE("Get Extended DPB: linear buffer address is %p\n", buffer);
+
+ /* validate passed-in buffer lengths */
+ if ((*buffer != 0x3d) || (context->Ecx != 0x3f))
+ {
+ WARN("Get Extended DPB: buffer lengths incorrect\n");
+ WARN("CX = %lx, buffer[0] = %x\n", context->Ecx, *buffer);
+ SET_CFLAG(context);
+ AL_reg(context) = 0x18; /* bad buffer length */
+ }
+
+ /* buffer checks out */
+ buffer++; /* skip over length word now */
+ if (FillInDrivePB( DX_reg(context) ) )
+ {
+ edpb = (struct EDPB *)buffer;
+
+ /* copy down the old-style DPB portion first */
+ memcpy(&edpb->dpb, &heap->dpb, sizeof(struct DPB));
+
+ /* now fill in the extended entries */
+ edpb->edpb_flags = 0;
+ edpb->next_edpb = 0;
+ edpb->free_cluster = edpb->free_cluster2 = 0;
+
+ /* determine free disk space */
+ *root += DOS_GET_DRIVE( DX_reg(context) );
+ GetDiskFreeSpaceA( root, &cluster_sectors, §or_bytes,
+ &free_clusters, &total_clusters );
+
+ edpb->clusters_free = (free_clusters&0xffff);
+
+ edpb->clusters_free_hi = free_clusters >> 16;
+ edpb->mirroring_flags = 0;
+ edpb->info_sector = 0xffff;
+ edpb->spare_boot_sector = 0xffff;
+ edpb->first_cluster = 0;
+ edpb->max_cluster = total_clusters;
+ edpb->fat_clusters = 32; /* made-up value */
+ edpb->root_cluster = 0;
+
+ RESET_CFLAG(context); /* clear carry */
+ AX_reg(context) = 0;
+ }
+ else
+ {
+ AX_reg(context) = 0x00ff;
+ SET_CFLAG(context);
+ }
+ }
+ break;
+
+ case 0x03: /* Get Extended free space on drive */
+ case 0x04: /* Set DPB for formatting */
+ case 0x05: /* extended absolute disk read/write */
+ FIXME("Unimplemented FAT32 int32 function %04x\n", AX_reg(context));
+ SET_CFLAG(context);
+ AL_reg(context) = 0;
+ break;
+ }
+
+ break;
+
+
case 0xdc: /* CONNECTION SERVICES - GET CONNECTION NUMBER */
case 0xea: /* NOVELL NETWARE - RETURN SHELL VERSION */
break;
default:
INT_BARF( context, 0x21 );
break;
+
+ } /* END OF SWITCH */
+
+ if( bSetDOSExtendedError ) /* set general error condition */
+ {
+ AX_reg(context) = GetLastError();
+ SET_CFLAG(context);
}
- dprintf_int( stddeb, "ret21: AX=%04x BX=%04x CX=%04x DX=%04x "
+
+ if ((context->EFlags & 0x0001))
+ TRACE("failed, error %ld\n", GetLastError() );
+
+ TRACE("returning: AX=%04x BX=%04x CX=%04x DX=%04x "
"SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08lx\n",
AX_reg(context), BX_reg(context), CX_reg(context),
DX_reg(context), SI_reg(context), DI_reg(context),
- (WORD)DS_reg(context), (WORD)ES_reg(context),
- EFL_reg(context));
+ (WORD)context->SegDs, (WORD)context->SegEs,
+ context->EFlags);
}
+
+/***********************************************************************
+ * GetSetKernelDOSProc (KERNEL.311)
+ */
+FARPROC16 WINAPI GetSetKernelDOSProc16(FARPROC16 DosProc)
+{
+ FIXME("(DosProc=0x%08x): stub\n", (UINT)DosProc);
+ return NULL;
+}
+