Newer
Older
#include "config.h"
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#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 "callback.h"
#include "task.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(int21);
#if defined(__svr4__) || defined(_SCO_DS)
/* SVR4 DOESNT do locking the same way must implement properly */
#define LOCK_EX 0
#define LOCK_SH 1
#define LOCK_NB 8
#endif
#define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive())
/* Define the drive parameter block, as used by int21/1F
* and int21/32. This table can be accessed through the
* global 'dpb' pointer, which points into the local dos
* heap.
*/
struct DPB
{
BYTE drive_num; /* 0=A, etc. */
BYTE unit_num; /* Drive's unit number (?) */
WORD sector_size; /* Sector size in bytes */
BYTE high_sector; /* Highest sector in a cluster */
BYTE shift; /* Shift count (?) */
WORD reserved; /* Number of reserved sectors at start */
BYTE num_FAT; /* Number of FATs */
WORD dir_entries; /* Number of root dir entries */
WORD first_data; /* First data sector */
WORD high_cluster; /* Highest cluster number */
WORD sectors_in_FAT; /* Number of sectors per FAT */
WORD start_dir; /* Starting sector of first dir */
DWORD driver_head; /* Address of device driver header (?) */
BYTE media_ID; /* Media ID */
BYTE access_flag; /* Prev. accessed flag (0=yes,0xFF=no) */
DWORD next; /* Pointer to next DPB in list */
WORD free_search; /* Free cluster search start */
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 */
};
BYTE DummyDBCSLeadTable[6];
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))))
{
WARN("Out of memory\n");
return FALSE;
}
heap = (struct DosHeap *) GlobalLock16(DosHeapHandle);
dpbsegptr = MAKESEGPTR(DosHeapHandle,(int)&heap->dpb-(int)heap);
heap->InDosFlag = 0;
strcpy(heap->biosdate, "01/01/80");
memset(heap->DummyDBCSLeadTable, 0, 6);
static BYTE *GetCurrentDTA( CONTEXT86 *context )
TDB *pTask = TASK_GetCurrent();
/* FIXME: This assumes DTA was set correctly! */
return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta),
void CreateBPB(int drive, BYTE *data, BOOL16 limited)
/* limited == TRUE is used with INT 0x21/0x440d */
{
if (drive > 1) {
setword(data, 512);
data[2] = 2;
setword(&data[3], 0);
data[5] = 2;
setword(&data[6], 240);
setword(&data[8], 64000);
data[0x0a] = 0xf8;
setword(&data[0x0b], 40);
setword(&data[0x0d], 56);
setword(&data[0x0f], 2);
setword(&data[0x11], 0);
if (!limited) {
setword(&data[0x1f], 800);
data[0x21] = 5;
setword(&data[0x22], 1);
}
} else { /* 1.44mb */
setword(data, 512);
data[2] = 2;
setword(&data[3], 0);
data[5] = 2;
setword(&data[6], 240);
setword(&data[8], 2880);
data[0x0a] = 0xf8;
setword(&data[0x0b], 6);
setword(&data[0x0d], 18);
setword(&data[0x0f], 2);
setword(&data[0x11], 0);
if (!limited) {
setword(&data[0x1f], 80);
data[0x21] = 7;
setword(&data[0x22], 2);
}
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 (!GetDiskFreeSpaceA( root, &cluster_sectors, §or_bytes,
&free_clusters, &total_clusters )) return 0;
AX_reg(context) = cluster_sectors;
BX_reg(context) = free_clusters;
CX_reg(context) = sector_bytes;
DX_reg(context) = total_clusters;
static int INT21_GetDriveAllocInfo( CONTEXT86 *context )
context->SegDs = DosHeapHandle;
BX_reg(context) = (int)&heap->mediaID - (int)heap;
return 1;
static int FillInDrivePB( int drive )
SetLastError( ERROR_INVALID_DRIVE );
{
/* 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
* getting at least _something_ back from here. The 'next' pointer
* does worry me, though. Should we have a complete table of
* separate DPBs per drive? Probably, but I'm lazy. :-) -CH
*/
heap->dpb.drive_num = heap->dpb.unit_num = drive; /*The same?*/
heap->dpb.sector_size = 512;
heap->dpb.high_sector = 1;
heap->dpb.shift = drive < 2 ? 0 : 6; /*6 for HD, 0 for floppy*/
heap->dpb.reserved = 0;
heap->dpb.num_FAT = 1;
heap->dpb.dir_entries = 2;
heap->dpb.first_data = 2;
heap->dpb.high_cluster = 64000;
heap->dpb.sectors_in_FAT = 1;
heap->dpb.start_dir = 1;
heap->dpb.driver_head = 0;
heap->dpb.media_ID = (drive > 1) ? 0xF8 : 0xF0;
heap->dpb.access_flag = 0;
heap->dpb.next = 0;
heap->dpb.free_search = 0;
heap->dpb.free_clusters = 0xFFFF; /* unknown */
return 0;
}
static void GetDrivePB( CONTEXT86 *context, int drive )
{
if (FillInDrivePB( drive ))
{
context->SegDs = SELECTOROF(dpbsegptr);
else
{
AX_reg(context) = 0x00ff;
}
static void ioctlGetDeviceInfo( CONTEXT86 *context )
TRACE("(%d)\n", BX_reg(context));
if ((dev = DOSFS_GetDeviceByHandle( DosFileHandleToWin32Handle(BX_reg(context)) )))
DX_reg(context) = dev->flags;
return;
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
static BOOL ioctlGenericBlkDevReq( CONTEXT86 *context )
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
SetLastError( ERROR_FILE_NOT_FOUND );
if (CH_reg(context) != 0x08)
{
INT_BARF( context, 0x21 );
TRACE("lock logical volume (%d) level %d mode %d\n",drive,BH_reg(context),DX_reg(context));
case 0x60: /* get device parameters */
/* used by w4wgrp's winfile */
memset(dataptr, 0, 0x20); /* DOS 6.22 uses 0x20 bytes */
dataptr[0] = 0x04;
dataptr[6] = 0; /* media type */
if (drive > 1)
{
dataptr[1] = 0x05; /* fixed disk */
setword(&dataptr[2], 0x01); /* non removable */
setword(&dataptr[4], 0x300); /* # of cylinders */
}
else
{
dataptr[1] = 0x07; /* block dev, floppy */
setword(&dataptr[2], 0x02); /* removable */
setword(&dataptr[4], 80); /* # of cylinders */
}
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;
DWORD serial;
strcpy(path,"x:\\");path[0]=drive+'A';
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);
}
TRACE("logical volume %d unlocked.\n",drive);
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;
static void INT21_ParseFileNameIntoFCB( CONTEXT86 *context )
{
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;
AL_reg(context) = 0xff; /* failed */
TRACE("filename: '%s'\n", filename);
buffer = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 1);
s = filename;
d = buffer;
while (*s)
{
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));
HeapFree( GetProcessHeap(), 0, buffer);
AL_reg(context) =
((strchr(filename, '*')) || (strchr(filename, '$'))) != 0;
/* point DS:SI to first unparsed character */
SI_reg(context) += (int)s - (int)filename;
}
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;
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);
/* Many calls translate a drive argument like this:
drive number (00h = default, 01h = A:, etc)
*/
static char drivestring[]="default";
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) );

Alexandre Julliard
committed
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,

Alexandre Julliard
committed
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

Alexandre Julliard
committed
}
static void OpenExistingFile( CONTEXT86 *context )
AX_reg(context) = _lopen16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
AX_reg(context) = GetLastError();
static BOOL INT21_ExtendedOpenCreateFile(CONTEXT86 *context )
BOOL bExtendedError = FALSE;
/* 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 ((context->EFlags & 0x0001) == 0) /* File exists */
_lclose16( AX_reg(context) );
WARN("extended open/create: failed because file exists \n");
/* Truncate it, but first check if opened for write */
_lclose16( AX_reg(context) );
WARN("extended open/create: failed, trunc on ro file\n");
AX_reg(context) = 0x000C; /*Access code invalid*/
SET_CFLAG(context);
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");
}
else uReturnCX = 0x1;
CX_reg(context) = uReturnCX;
}
RESET_CFLAG(context); /* was set by OpenExistingFile(context) */
WARN("extended open/create: failed, file dosen't exist\n");
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;
static BOOL INT21_ChangeDir( CONTEXT86 *context )
char *dirname = CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx);
TRACE("changedir %s\n", dirname);
{
drive = toupper(dirname[0]) - 'A';
dirname += 2;
}
else drive = DRIVE_GetCurrentDrive();
static int INT21_FindFirst( CONTEXT86 *context )
FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
AX_reg(context) = GetLastError();
dta->unixPath = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
strcpy( dta->unixPath, full_name.long_name );
/* 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 ))
SetLastError( ERROR_FILE_NOT_FOUND );
AX_reg(context) = ERROR_FILE_NOT_FOUND;
dta->drive = (path[0] && (path[1] == ':')) ? toupper(path[0]) - 'A'
: DRIVE_GetCurrentDrive();
dta->count = 0;
dta->search_attr = CL_reg(context);
return 1;
static int INT21_FindNext( CONTEXT86 *context )
FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
WIN32_FIND_DATAA entry;
if (!(count = DOSFS_FindNext( dta->unixPath, dta->mask, NULL, dta->drive,
dta->unixPath = NULL;
return 0;
}
if ((int)dta->count + count > 0xffff)
{
WARN("Too many directory entries in %s\n", dta->unixPath );
dta->unixPath = NULL;
return 0;
}
dta->count += count;
dta->fileattr = entry.dwFileAttributes;
dta->filesize = entry.nFileSizeLow;
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;
}
static BOOL INT21_CreateTempFile( CONTEXT86 *context )
char *name = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx );
/* 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 );
if ((AX_reg(context) = _lcreat16_uniq( name, 0 )) != (WORD)HFILE_ERROR16)
TRACE("created %s\n", name );
if (GetLastError() != ERROR_FILE_EXISTS) return FALSE;
static BOOL INT21_GetCurrentDirectory( CONTEXT86 *context )
char *ptr = (char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi );
SetLastError( ERROR_INVALID_DRIVE );
lstrcpynA( ptr, DRIVE_GetDosCwd(drive), 64 );
AX_reg(context) = 0x0100; /* success return code */
return TRUE;
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( CONTEXT86 *context )
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
SetLastError( ERROR_INVALID_DRIVE );
return 0;
}
*(WORD *)dataptr = 0;
*(DWORD *)(dataptr + 2) = DRIVE_GetSerialNumber( drive );
memcpy( dataptr + 6, DRIVE_GetLabel( drive ), 11 );
strncpy(dataptr + 0x11, "FAT16 ", 8);
return 1;
static int INT21_SetDiskSerialNumber( CONTEXT86 *context )
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
SetLastError( ERROR_INVALID_DRIVE );
DRIVE_SetSerialNumber( drive, *(DWORD *)(dataptr + 2) );
return 1;
/* microsoft's programmers should be shot for using CP/M style int21
calls in Windows for Workgroup's winfile.exe */
static int INT21_FindFirstFCB( CONTEXT86 *context )
BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
if (*fcb == 0xff) pFCB = (FINDFILE_FCB *)(fcb + 7);
else pFCB = (FINDFILE_FCB *)fcb;
drive = DOS_GET_DRIVE( pFCB->drive );
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 );
static int INT21_FindNextFCB( CONTEXT86 *context )
BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
WIN32_FIND_DATAA entry;
{
attr = fcb[6];
pFCB = (FINDFILE_FCB *)(fcb + 7);
}
else
{
attr = 0;
pFCB = (FINDFILE_FCB *)fcb;
}
if (!(count = DOSFS_FindNext( pFCB->unixPath, pFCB->filename, NULL,
DOS_GET_DRIVE( pFCB->drive ), attr,
pFCB->count, &entry )))
{
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->filesize = entry.nFileSizeLow;
memset( pResult->reserved, 0, sizeof(pResult->reserved) );
FileTimeToDosDateTime( &entry.ftLastWriteTime,
&pResult->filedate, &pResult->filetime );
/* Convert file name to FCB format */
memset( pResult->filename, ' ', sizeof(pResult->filename) );
if (!strcmp( entry.cAlternateFileName, "." )) pResult->filename[0] = '.';
else if (!strcmp( entry.cAlternateFileName, ".." ))
pResult->filename[0] = pResult->filename[1] = '.';
else
{
char *p = strrchr( entry.cAlternateFileName, '.' );
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 ) );
}
else
memcpy( pResult->filename, entry.cAlternateFileName,
min( strlen(entry.cAlternateFileName), 8 ) );
static void DeleteFileFCB( CONTEXT86 *context )
FIXME("(%p): stub\n", context);
static void RenameFileFCB( CONTEXT86 *context )
FIXME("(%p): stub\n", context);
static void fLock( CONTEXT86 * context )
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();
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();
static BOOL
INT21_networkfunc (CONTEXT86 *context)
{
switch (AL_reg(context)) {
case 0x00: /* Get machine name. */
{
char *dst = CTX_SEG_OFF_TO_LIN (context,context->SegDs,context->Edx);
TRACE("getting machine name to %p\n", dst);
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));
SetLastError( ER_NoNetwork );
static void ASPI_DOS_HandleInt( CONTEXT86 *context )
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();
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;