*
* 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
-#include <sys/stat.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "wine/debug.h"
#include "wine/exception.h"
+BOOL WINAPI VerifyConsoleIoHandle(HANDLE);
/*
* Note:
* - Most of the file related functions are wrong. NT's kernel32
* doesn't maintain a per drive current directory, while DOS does.
- * We should in fact keep track in here of those per driver
- * directories, and use this infro while dealing with partial paths
+ * We should in fact keep track in here of those per drive
+ * directories, and use this info while dealing with partial paths
* (drive defined, but only relative paths). This could even be
* created as an array of CDS (there should be an entry for that in
* the LOL)
#define EL_Serial 0x04
#define EL_Memory 0x05
+/* BIOS Keyboard Scancodes */
+#define KEY_LEFT 0x4B
+#define KEY_RIGHT 0x4D
+#define KEY_UP 0x48
+#define KEY_DOWN 0x50
+#define KEY_IC 0x52 /* insert char */
+#define KEY_DC 0x53 /* delete char */
+#define KEY_BACKSPACE 0x0E
+#define KEY_HOME 0x47
+#define KEY_END 0x4F
+#define KEY_NPAGE 0x49
+#define KEY_PPAGE 0x51
+
struct magic_device
{
WCHAR name[10];
HANDLE handle;
- dev_t dev;
- ino_t ino;
+ LARGE_INTEGER index;
void (*ioctl_handler)(CONTEXT86 *);
};
static struct magic_device magic_devices[] =
{
- { {'s','c','s','i','m','g','r','$',0}, NULL, 0, 0, INT21_IoctlScsiMgrHandler },
- { {'e','m','m','x','x','x','x','0',0}, NULL, 0, 0, INT21_IoctlEMSHandler },
- { {'h','p','s','c','a','n',0}, NULL, 0, 0, INT21_IoctlHPScanHandler },
+ { {'s','c','s','i','m','g','r','$',0}, NULL, { { 0, 0 } }, INT21_IoctlScsiMgrHandler },
+ { {'e','m','m','x','x','x','x','0',0}, NULL, { { 0, 0 } }, INT21_IoctlEMSHandler },
+ { {'h','p','s','c','a','n',0}, NULL, { { 0, 0 } }, INT21_IoctlHPScanHandler },
};
#define NB_MAGIC_DEVICES (sizeof(magic_devices)/sizeof(magic_devices[0]))
* INT21_FillHeap
*
* Initialize DOS heap.
+ *
+ * Filename Terminator Table of w2k DE NTVDM:
+ * 16 00 01 00 FF 00 00 20-02 0E 2E 22 2F 5C 5B 5D ....... ..."/\[]
+ * 3A 7C 3C 3E 2B 3D 3B 2C-00 :|<>+=;,
*/
static void INT21_FillHeap( INT21_HEAP *heap )
{
- static const char terminators[] = "\"\\./[]:|<>+=;,";
+ static const char terminators[] = ".\"/\\[]:|<>+=;,";
int i;
/*
*/
heap->filename_size = 8 + strlen(terminators);
heap->filename_illegal_size = strlen(terminators);
- strcpy( heap->filename_illegal_table, terminators );
+ memcpy( heap->filename_illegal_table, terminators, heap->filename_illegal_size );
heap->filename_reserved1 = 0x01;
- heap->filename_lowest = 0; /* FIXME: correct value? */
- heap->filename_highest = 0xff; /* FIXME: correct value? */
+ heap->filename_lowest = 0x00;
+ heap->filename_highest = 0xff;
heap->filename_reserved2 = 0x00;
- heap->filename_exclude_first = 0x00; /* FIXME: correct value? */
- heap->filename_exclude_last = 0x00; /* FIXME: correct value? */
+ heap->filename_exclude_first = 0x00;
+ heap->filename_exclude_last = 0x20;
heap->filename_reserved3 = 0x02;
/*
static BOOL INT21_GetCurrentDirectory( CONTEXT86 *context, BOOL islong )
{
char *buffer = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi);
- BYTE new_drive = INT21_MapDrive( DL_reg(context) );
- BYTE old_drive = INT21_GetCurrentDrive();
+ BYTE drive = INT21_MapDrive( DL_reg(context) );
WCHAR pathW[MAX_PATH];
char pathA[MAX_PATH];
WCHAR *ptr = pathW;
TRACE( "drive %d\n", DL_reg(context) );
- if (new_drive == MAX_DOS_DRIVES)
- {
+ if (drive == MAX_DOS_DRIVES)
+ {
SetLastError(ERROR_INVALID_DRIVE);
return FALSE;
}
* Grab current directory.
*/
- INT21_SetCurrentDrive( new_drive );
- if (!GetCurrentDirectoryW( MAX_PATH, pathW ))
- {
- INT21_SetCurrentDrive( old_drive );
- return FALSE;
+ if (!GetCurrentDirectoryW( MAX_PATH, pathW )) return FALSE;
+
+ if (toupperW(pathW[0]) - 'A' != drive || pathW[1] != ':')
+ {
+ /* cwd is not on the requested drive, get the environment string instead */
+
+ WCHAR env_var[4];
+
+ env_var[0] = '=';
+ env_var[1] = 'A' + drive;
+ env_var[2] = ':';
+ env_var[3] = 0;
+ if (!GetEnvironmentVariableW( env_var, pathW, MAX_PATH ))
+ {
+ /* return empty path */
+ buffer[0] = 0;
+ return TRUE;
+ }
}
- INT21_SetCurrentDrive( old_drive );
/*
* Convert into short format.
pathA[63] = 0;
}
- TRACE( "%c:=%s\n", 'A' + new_drive, pathA );
+ TRACE( "%c:=%s\n", 'A' + drive, pathA );
strcpy( buffer, pathA );
return TRUE;
static BOOL INT21_SetCurrentDirectory( CONTEXT86 *context )
{
WCHAR dirW[MAX_PATH];
+ WCHAR env_var[4];
+ DWORD attr;
char *dirA = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
BYTE drive = INT21_GetCurrentDrive();
BOOL result;
TRACE( "SET CURRENT DIRECTORY %s\n", dirA );
MultiByteToWideChar(CP_OEMCP, 0, dirA, -1, dirW, MAX_PATH);
- result = SetCurrentDirectoryW( dirW );
+ if (!GetFullPathNameW( dirW, MAX_PATH, dirW, NULL )) return FALSE;
+
+ attr = GetFileAttributesW( dirW );
+ if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ SetLastError( ERROR_PATH_NOT_FOUND );
+ return FALSE;
+ }
+
+ env_var[0] = '=';
+ env_var[1] = dirW[0];
+ env_var[2] = ':';
+ env_var[3] = 0;
+ result = SetEnvironmentVariableW( env_var, dirW );
- /* This function must not change current drive. */
- INT21_SetCurrentDrive( drive );
+ /* only set current directory if on the current drive */
+ if (result && (toupperW(dirW[0]) - 'A' == drive)) result = SetCurrentDirectoryW( dirW );
return result;
}
*/
static HANDLE INT21_CreateMagicDeviceHandle( LPCWSTR name )
{
+ static const WCHAR prefixW[] = {'\\','?','?','\\','u','n','i','x'};
const char *dir = wine_get_server_dir();
int len;
HANDLE ret;
IO_STATUS_BLOCK io;
len = MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, NULL, 0 );
- nameW.Length = (len + 1 + strlenW( name )) * sizeof(WCHAR);
+ nameW.Length = sizeof(prefixW) + (len + strlenW( name )) * sizeof(WCHAR);
nameW.MaximumLength = nameW.Length + sizeof(WCHAR);
- if (!(nameW.Buffer = HeapAlloc( GetProcessHeap(), 0, nameW.Length )))
+ if (!(nameW.Buffer = HeapAlloc( GetProcessHeap(), 0, nameW.MaximumLength )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
- MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, nameW.Buffer, len );
+ memcpy( nameW.Buffer, prefixW, sizeof(prefixW) );
+ MultiByteToWideChar( CP_UNIXCP, 0, dir, -1, nameW.Buffer + sizeof(prefixW)/sizeof(WCHAR), len );
+ len += sizeof(prefixW) / sizeof(WCHAR);
nameW.Buffer[len-1] = '/';
strcpyW( nameW.Buffer + len, name );
*/
static HANDLE INT21_OpenMagicDevice( LPCWSTR name, DWORD access )
{
- int i;
+ unsigned int i;
const WCHAR *p;
HANDLE handle;
if (!magic_devices[i].handle) /* need to open it */
{
- int fd;
- struct stat st;
+ IO_STATUS_BLOCK io;
+ FILE_INTERNAL_INFORMATION info;
if (!(handle = INT21_CreateMagicDeviceHandle( magic_devices[i].name ))) return 0;
- wine_server_handle_to_fd( handle, 0, &fd, NULL, NULL );
- fstat( fd, &st );
- wine_server_release_fd( handle, fd );
- magic_devices[i].dev = st.st_dev;
- magic_devices[i].ino = st.st_ino;
+
+ NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
+ magic_devices[i].index = info.IndexNumber;
magic_devices[i].handle = handle;
}
if (!DuplicateHandle( GetCurrentProcess(), magic_devices[i].handle,
{
WORD dosAttributes = CX_reg(context);
- if (dosAttributes & FILE_ATTRIBUTE_LABEL)
+ if (dosAttributes & FA_LABEL)
{
/*
* Application tried to create volume label entry.
{
winHandle = CreateFileW( pathW, winAccess, winSharing, NULL,
winMode, winAttributes, 0 );
+ /* DOS allows to open files on a CDROM R/W */
+ if( winHandle == INVALID_HANDLE_VALUE &&
+ GetLastError()== ERROR_WRITE_PROTECT) {
+ winHandle = CreateFileW( pathW, winAccess & ~GENERIC_WRITE,
+ winSharing, NULL, winMode, winAttributes, 0 );
+ }
if (winHandle == INVALID_HANDLE_VALUE)
return FALSE;
if (ascii == '\r' || ascii == '\n')
{
- /*
- * FIXME: What should be echoed here?
- */
- DOSVM_PutChar( '\r' );
- DOSVM_PutChar( '\n' );
ptr[length] = '\r';
return length + 1;
}
/*
- * FIXME: This function is supposed to support
- * DOS editing keys...
+ * DOS handles only backspace and KEY_LEFT
+ * perhaps we should do more
*/
+ if (ascii == '\b' || scan == KEY_LEFT)
+ {
+ if (length==0) continue;
+ DOSVM_PutChar( '\b' );
+ length--;
+ continue;
+ }
/*
* If the buffer becomes filled to within one byte of
struct XFCB *xfcb;
HANDLE handle;
DWORD record_number;
- long position;
+ DWORD position;
BYTE *disk_transfer_area;
UINT bytes_read;
BYTE AL_result;
record_number = 128 * fcb->current_block_number + fcb->record_within_current_block;
position = SetFilePointer(handle, record_number * fcb->logical_record_size, NULL, 0);
if (position != record_number * fcb->logical_record_size) {
- TRACE("seek(%d, %ld, 0) failed with %ld\n",
+ TRACE("seek(%d, %d, 0) failed with %u\n",
fcb->file_number, record_number * fcb->logical_record_size, position);
AL_result = 0x01; /* end of file, no data read */
} else {
AL_result = 0x03; /* end of file, partial record read */
} /* if */
} else {
- TRACE("successful read %d bytes from record %ld (position %ld) of file %d (handle %p)\n",
+ TRACE("successful read %d bytes from record %d (position %u) of file %d (handle %p)\n",
bytes_read, record_number, position, fcb->file_number, handle);
AL_result = 0x00; /* successful */
} /* if */
struct XFCB *xfcb;
HANDLE handle;
DWORD record_number;
- long position;
+ DWORD position;
BYTE *disk_transfer_area;
UINT bytes_written;
BYTE AL_result;
record_number = 128 * fcb->current_block_number + fcb->record_within_current_block;
position = SetFilePointer(handle, record_number * fcb->logical_record_size, NULL, 0);
if (position != record_number * fcb->logical_record_size) {
- TRACE("seek(%d, %ld, 0) failed with %ld\n",
+ TRACE("seek(%d, %d, 0) failed with %u\n",
fcb->file_number, record_number * fcb->logical_record_size, position);
AL_result = 0x01; /* disk full */
} else {
disk_transfer_area = INT21_GetCurrentDTA(context);
- bytes_written = _lwrite((HFILE) handle, disk_transfer_area, fcb->logical_record_size);
+ bytes_written = _lwrite((HFILE) handle, (LPCSTR)disk_transfer_area, fcb->logical_record_size);
if (bytes_written != fcb->logical_record_size) {
TRACE("_lwrite(%d, %p, %d) failed with %d\n",
fcb->file_number, disk_transfer_area, fcb->logical_record_size, bytes_written);
AL_result = 0x01; /* disk full */
} else {
- TRACE("successful written %d bytes from record %ld (position %ld) of file %d (handle %p)\n",
+ TRACE("successful written %d bytes from record %d (position %u) of file %d (handle %p)\n",
bytes_written, record_number, position, fcb->file_number, handle);
AL_result = 0x00; /* successful */
} /* if */
struct XFCB *xfcb;
HANDLE handle;
DWORD record_number;
- long position;
+ DWORD position;
BYTE *disk_transfer_area;
UINT bytes_read;
BYTE AL_result;
} else {
position = SetFilePointer(handle, record_number * fcb->logical_record_size, NULL, 0);
if (position != record_number * fcb->logical_record_size) {
- TRACE("seek(%d, %ld, 0) failed with %ld\n",
+ TRACE("seek(%d, %d, 0) failed with %u\n",
fcb->file_number, record_number * fcb->logical_record_size, position);
AL_result = 0x01; /* end of file, no data read */
} else {
AL_result = 0x03; /* end of file, partial record read */
} /* if */
} else {
- TRACE("successful read %d bytes from record %ld (position %ld) of file %d (handle %p)\n",
+ TRACE("successful read %d bytes from record %d (position %u) of file %d (handle %p)\n",
bytes_read, record_number, position, fcb->file_number, handle);
AL_result = 0x00; /* successful */
} /* if */
struct XFCB *xfcb;
HANDLE handle;
DWORD record_number;
- long position;
+ DWORD position;
BYTE *disk_transfer_area;
UINT bytes_written;
BYTE AL_result;
} else {
position = SetFilePointer(handle, record_number * fcb->logical_record_size, NULL, 0);
if (position != record_number * fcb->logical_record_size) {
- TRACE("seek(%d, %ld, 0) failed with %ld\n",
+ TRACE("seek(%d, %d, 0) failed with %u\n",
fcb->file_number, record_number * fcb->logical_record_size, position);
AL_result = 0x01; /* disk full */
} else {
disk_transfer_area = INT21_GetCurrentDTA(context);
- bytes_written = _lwrite((HFILE) handle, disk_transfer_area, fcb->logical_record_size);
+ bytes_written = _lwrite((HFILE) handle, (LPCSTR)disk_transfer_area, fcb->logical_record_size);
if (bytes_written != fcb->logical_record_size) {
TRACE("_lwrite(%d, %p, %d) failed with %d\n",
fcb->file_number, disk_transfer_area, fcb->logical_record_size, bytes_written);
AL_result = 0x01; /* disk full */
} else {
- TRACE("successful written %d bytes from record %ld (position %ld) of file %d (handle %p)\n",
+ TRACE("successful written %d bytes from record %d (position %u) of file %d (handle %p)\n",
bytes_written, record_number, position, fcb->file_number, handle);
AL_result = 0x00; /* successful */
} /* if */
struct XFCB *xfcb;
HANDLE handle;
DWORD record_number;
- long position;
+ DWORD position;
BYTE *disk_transfer_area;
UINT records_requested;
UINT bytes_requested;
} else {
position = SetFilePointer(handle, record_number * fcb->logical_record_size, NULL, 0);
if (position != record_number * fcb->logical_record_size) {
- TRACE("seek(%d, %ld, 0) failed with %ld\n",
+ TRACE("seek(%d, %d, 0) failed with %u\n",
fcb->file_number, record_number * fcb->logical_record_size, position);
records_read = 0;
AL_result = 0x01; /* end of file, no data read */
} else {
disk_transfer_area = INT21_GetCurrentDTA(context);
records_requested = CX_reg(context);
- bytes_requested = (UINT) records_requested * fcb->logical_record_size;
+ bytes_requested = records_requested * fcb->logical_record_size;
bytes_read = _lread((HFILE) handle, disk_transfer_area, bytes_requested);
if (bytes_read != bytes_requested) {
TRACE("_lread(%d, %p, %d) failed with %d\n",
AL_result = 0x03; /* end of file, partial record read */
} /* if */
} else {
- TRACE("successful read %d bytes from record %ld (position %ld) of file %d (handle %p)\n",
+ TRACE("successful read %d bytes from record %d (position %u) of file %d (handle %p)\n",
bytes_read, record_number, position, fcb->file_number, handle);
records_read = records_requested;
AL_result = 0x00; /* successful */
struct XFCB *xfcb;
HANDLE handle;
DWORD record_number;
- long position;
+ DWORD position;
BYTE *disk_transfer_area;
UINT records_requested;
UINT bytes_requested;
} else {
position = SetFilePointer(handle, record_number * fcb->logical_record_size, NULL, 0);
if (position != record_number * fcb->logical_record_size) {
- TRACE("seek(%d, %ld, 0) failed with %ld\n",
+ TRACE("seek(%d, %d, 0) failed with %u\n",
fcb->file_number, record_number * fcb->logical_record_size, position);
records_written = 0;
AL_result = 0x01; /* disk full */
} else {
disk_transfer_area = INT21_GetCurrentDTA(context);
records_requested = CX_reg(context);
- bytes_requested = (UINT) records_requested * fcb->logical_record_size;
- bytes_written = _lwrite((HFILE) handle, disk_transfer_area, bytes_requested);
+ bytes_requested = records_requested * fcb->logical_record_size;
+ bytes_written = _lwrite((HFILE) handle, (LPCSTR)disk_transfer_area, bytes_requested);
if (bytes_written != bytes_requested) {
TRACE("_lwrite(%d, %p, %d) failed with %d\n",
fcb->file_number, disk_transfer_area, bytes_requested, bytes_written);
records_written = bytes_written / fcb->logical_record_size;
AL_result = 0x01; /* disk full */
} else {
- TRACE("successful write %d bytes from record %ld (position %ld) of file %d (handle %p)\n",
+ TRACE("successful write %d bytes from record %d (position %u) of file %d (handle %p)\n",
bytes_written, record_number, position, fcb->file_number, handle);
records_written = records_requested;
AL_result = 0x00; /* successful */
static void INT21_ExtendedCountryInformation( CONTEXT86 *context )
{
BYTE *dataptr = CTX_SEG_OFF_TO_LIN( context, context->SegEs, context->Edi );
-
+ BYTE buffsize = CX_reg (context);
+
TRACE( "GET EXTENDED COUNTRY INFORMATION, subfunction %02x\n",
AL_reg(context) );
*(WORD*)(dataptr+1) = 38; /* Size of the following info */
*(WORD*)(dataptr+3) = INT21_GetSystemCountryCode(); /* Country ID */
*(WORD*)(dataptr+5) = GetOEMCP(); /* Code page */
- INT21_FillCountryInformation( dataptr + 7 );
- SET_CX( context, 41 ); /* Size of returned info */
+ /* FIXME: fill buffer partially up to buffsize bytes*/
+ if (buffsize >= 0x29){
+ INT21_FillCountryInformation( dataptr + 7 );
+ SET_CX( context, 0x29 ); /* Size of returned info */
+ }else{
+ SET_CX( context, 0x07 ); /* Size of returned info */
+ }
break;
case 0x02: /* GET POINTER TO UPPERCASE TABLE */
case 0x22: /* CAPITALIZE ASCIIZ STRING */
case 0xa2: /* CAPITALIZE ASCIIZ FILENAME */
TRACE("Convert ASCIIZ string to uppercase\n");
- _strupr( (LPSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx) );
+ {
+ char *p = CTX_SEG_OFF_TO_LIN( context, context->SegDs, context->Edx );
+ for ( ; *p; p++) *p = toupper(*p);
+ }
break;
case 0x23: /* DETERMINE IF CHARACTER REPRESENTS YES/NO RESPONSE */
}
}
+static inline DWORD INT21_Ioctl_CylHeadSect2Lin(DWORD cyl, WORD head, WORD sec, WORD cyl_cnt,
+ WORD head_cnt, WORD sec_cnt)
+{
+ DWORD res = (cyl * head_cnt*sec_cnt + head * sec_cnt + sec);
+ return res;
+}
+
/***********************************************************************
* INT21_Ioctl_Block
*
break;
case 0x0d: /* GENERIC BLOCK DEVICE REQUEST */
- /* Get pointer to IOCTL parameter block. */
+ /* Get pointer to IOCTL parameter block */
dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
switch (CX_reg(context))
TRACE( "GENERIC IOCTL - Write logical device track - %c:\n",
'A' + drive);
{
- 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; /* FIXME: is this correct? */
+ WORD head = *(WORD *)(dataptr+1);
+ WORD cyl = *(WORD *)(dataptr+3);
+ WORD sect = *(WORD *)(dataptr+5);
+ WORD nrsect = *(WORD *)(dataptr+7);
+ BYTE *data = CTX_SEG_OFF_TO_LIN(context, *(WORD *)(dataptr+11), *(WORD *)(dataptr+9));
+ WORD cyl_cnt, head_cnt, sec_cnt;
+
+ /* FIXME: we're faking some values here */
+ if (drive > 1)
+ {
+ /* cyl_cnt = 0x300;
+ head_cnt = 16;
+ sec_cnt = 255; */
+ SET_AX( context, ERROR_WRITE_FAULT );
+ SET_CFLAG(context);
+ break;
+ }
+ else
+ { /* floppy */
+ cyl_cnt = 80;
+ head_cnt = 2;
+ sec_cnt = 18;
+ }
- if (!DOSVM_RawWrite(drive, head*cyl*sect, nrsect, data, FALSE))
+ if (!DOSVM_RawWrite(drive, INT21_Ioctl_CylHeadSect2Lin(cyl, head, sect, cyl_cnt, head_cnt, sec_cnt), nrsect, data, FALSE))
{
SET_AX( context, ERROR_WRITE_FAULT );
SET_CFLAG(context);
TRACE( "GENERIC IOCTL - Read logical device track - %c:\n",
'A' + drive);
{
- 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; /* FIXME: is this correct? */
+ WORD head = *(WORD *)(dataptr+1);
+ WORD cyl = *(WORD *)(dataptr+3);
+ WORD sect = *(WORD *)(dataptr+5);
+ WORD nrsect = *(WORD *)(dataptr+7);
+ BYTE *data = CTX_SEG_OFF_TO_LIN(context, *(WORD *)(dataptr+11), *(WORD *)(dataptr+9));
+ WORD cyl_cnt, head_cnt, sec_cnt;
+
+ /* FIXME: we're faking some values here */
+ if (drive > 1)
+ {
+ cyl_cnt = 0x300;
+ head_cnt = 16;
+ sec_cnt = 255;
+ }
+ else
+ { /* floppy */
+ cyl_cnt = 80;
+ head_cnt = 2;
+ sec_cnt = 18;
+ }
- if (!DOSVM_RawRead(drive, head*cyl*sect, nrsect, data, FALSE))
+ if (!DOSVM_RawRead(drive, INT21_Ioctl_CylHeadSect2Lin(cyl, head, sect, cyl_cnt, head_cnt, sec_cnt), nrsect, data, FALSE))
{
SET_AX( context, ERROR_READ_FAULT );
SET_CFLAG(context);
GetVolumeInformationW(drivespec, label, 12, &serial, NULL, NULL, fsname, 9);
*(WORD*)dataptr = 0;
memcpy(dataptr+2,&serial,4);
- WideCharToMultiByte(CP_OEMCP, 0, label, 11, dataptr + 6, 11, NULL, NULL);
- WideCharToMultiByte(CP_OEMCP, 0, fsname, 8, dataptr + 17, 8, NULL, NULL);
+ WideCharToMultiByte(CP_OEMCP, 0, label, 11, (LPSTR)dataptr + 6, 11, NULL, NULL);
+ WideCharToMultiByte(CP_OEMCP, 0, fsname, 8, (LPSTR)dataptr + 17, 8, NULL, NULL);
}
break;
break;
case 0x0872:
- /* Trail on error implementation */
+ /* Trial and error implementation */
SET_AX( context, drivetype == DRIVE_UNKNOWN ? 0x0f : 0x01 );
SET_CFLAG(context); /* Seems to be set all the time */
break;
break;
case 0x0f: /* SET LOGICAL DRIVE MAP */
- {
- WCHAR dev[3], tgt[4];
-
- TRACE("IOCTL - SET LOGICAL DRIVE MAP for drive %s\n",
- INT21_DriveName( BL_reg(context)));
- dev[0] = 'A' + drive; dev[1] = ':'; dev[2] = 0;
- tgt[0] = 'A' + drive + 1; dev[1] = ':'; dev[2] = '\\'; dev[3] = 0;
- if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, dev, tgt))
- {
- SET_CFLAG(context);
- SET_AX( context, 0x000F ); /* invalid drive */
- }
- }
+ TRACE("IOCTL - SET LOGICAL DRIVE MAP for drive %s\n",
+ INT21_DriveName( BL_reg(context)));
+ /* FIXME: as of today, we don't support logical drive mapping... */
+ SET_AL( context, 0 );
break;
case 0x11: /* QUERY GENERIC IOCTL CAPABILITY */
*/
static void INT21_Ioctl_Char( CONTEXT86 *context )
{
- struct stat st;
- int status, i, fd;
+ int status;
+ int IsConsoleIOHandle = 0;
+ IO_STATUS_BLOCK io;
+ FILE_INTERNAL_INFORMATION info;
HANDLE handle = DosFileHandleToWin32Handle(BX_reg(context));
- status = wine_server_handle_to_fd( handle, 0, &fd, NULL, NULL );
+ status = NtQueryInformationFile( handle, &io, &info, sizeof(info), FileInternalInformation );
if (status)
{
- SET_AX( context, RtlNtStatusToDosError(status) );
- SET_CFLAG( context );
- return;
- }
- fstat( fd, &st );
- wine_server_release_fd( handle, fd );
-
- for (i = 0; i < NB_MAGIC_DEVICES; i++)
- {
- if (!magic_devices[i].handle) continue;
- if (magic_devices[i].dev == st.st_dev && magic_devices[i].ino == st.st_ino)
- {
- /* found it */
- magic_devices[i].ioctl_handler( context );
+ if( VerifyConsoleIoHandle( handle))
+ IsConsoleIOHandle = 1;
+ else {
+ SET_AX( context, RtlNtStatusToDosError(status) );
+ SET_CFLAG( context );
return;
}
+ } else {
+ UINT i;
+ for (i = 0; i < NB_MAGIC_DEVICES; i++)
+ {
+ if (!magic_devices[i].handle) continue;
+ if (magic_devices[i].index.QuadPart == info.IndexNumber.QuadPart)
+ {
+ /* found it */
+ magic_devices[i].ioctl_handler( context );
+ return;
+ }
+ }
}
/* no magic device found, do default handling */
{
case 0x00: /* GET DEVICE INFORMATION */
TRACE( "IOCTL - GET DEVICE INFORMATION - %d\n", BX_reg(context) );
- if (S_ISCHR(st.st_mode))
+ if (IsConsoleIOHandle || GetFileType(handle) == FILE_TYPE_CHAR)
{
/*
* Returns attribute word in DX:
* Bit 4 - Device is special (uses int29).
* Bit 3 - Clock device.
* Bit 2 - NUL device.
- * Bit 1 - Standard output.
- * Bit 0 - Standard input.
+ * Bit 1 - Console output device.
+ * Bit 0 - Console input device.
*/
- SET_DX( context, 0x80c0 /* FIXME */ );
+ SET_DX( context, IsConsoleIOHandle ? 0x80c3 : 0x80c0 /* FIXME */ );
}
else
{
source = &INT21_GetHeapPointer()->misc_dpb_list[drive];
*ptr = sizeof(INT21_DPB);
- memcpy( target, source, sizeof(INT21_DPB));
+ *target = *source;
if (LOWORD(context->Esi) != 0xF1A6)
{
switch (CL_reg(context))
{
+ case 0x00: /* "truename" - Canonicalize path */
+ /*
+ * FIXME: This is not 100% equal to 0x01 case,
+ * if you fix this, fix int21 subfunction 0x60, too.
+ */
+
case 0x01: /* Get short filename or path */
MultiByteToWideChar(CP_OEMCP, 0, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi), -1, pathW, MAX_PATH);
if (!GetShortPathNameW(pathW, res, 67))
*(WORD *)dataptr = 0;
memcpy(dataptr + 2, &serial, sizeof(DWORD));
- WideCharToMultiByte(CP_OEMCP, 0, label, 11, dataptr + 6, 11, NULL, NULL);
- strncpy(dataptr + 17, "FAT16 ", 8);
+ WideCharToMultiByte(CP_OEMCP, 0, label, 11, (LPSTR)dataptr + 6, 11, NULL, NULL);
+ memcpy(dataptr + 17, "FAT16 ", 8);
return 1;
}
{
DWORD cluster_sectors, sector_bytes, free_clusters, total_clusters;
WCHAR root[] = {'A',':','\\',0};
+ const DWORD max_clusters = 0x3d83;
+ const DWORD max_sectors_per_cluster = 0x7f;
+ const DWORD max_bytes_per_sector = 0x200;
root[0] += INT21_MapDrive(DL_reg(context));
if (!GetDiskFreeSpaceW( root, &cluster_sectors, §or_bytes,
&free_clusters, &total_clusters )) return 0;
+
+ /* Some old win31 apps (Lotus SmartSuite 5.1) crap out if there's too
+ * much disk space, so Windows XP seems to apply the following limits:
+ * cluster_sectors <= 0x7f
+ * sector size <= 0x200
+ * clusters <= 0x3D83
+ * This means total reported space is limited to about 1GB.
+ */
+
+ /* Make sure bytes-per-sector is in [, max] */
+ while (sector_bytes > max_bytes_per_sector) {
+ sector_bytes >>= 1;
+ free_clusters <<= 1;
+ total_clusters <<= 1;
+ }
+ /* Then make sure sectors-per-cluster is in [max/2, max]. */
+ while (cluster_sectors <= max_sectors_per_cluster/2) {
+ cluster_sectors <<= 1;
+ free_clusters >>= 1;
+ total_clusters >>= 1;
+ }
+ while (cluster_sectors > max_sectors_per_cluster) {
+ cluster_sectors >>= 1;
+ free_clusters <<= 1;
+ total_clusters <<= 1;
+ }
+
+ /* scale up sectors_per_cluster to exactly max_sectors_per_cluster.
+ * We could skip this, but that would impose an artificially low
+ * limit on reported disk space.
+ * To avoid overflow, first apply a preliminary cap on sector count;
+ * this will not affect the correctness of the final result,
+ * because if the preliminary cap hits, the final one will, too.
+ */
+ if (total_clusters > 4 * max_clusters)
+ total_clusters = 4 * max_clusters;
+ if (free_clusters > 4 * max_clusters)
+ free_clusters = 4 * max_clusters;
+ if (cluster_sectors < max_sectors_per_cluster) {
+ free_clusters *= cluster_sectors;
+ free_clusters /= max_sectors_per_cluster;
+ total_clusters *= cluster_sectors;
+ total_clusters /= max_sectors_per_cluster;
+ cluster_sectors = max_sectors_per_cluster;
+ }
+
+ /* Finally, apply real cluster count cap. */
+ if (total_clusters > max_clusters)
+ total_clusters = max_clusters;
+ if (free_clusters > max_clusters)
+ free_clusters = max_clusters;
+
SET_AX( context, cluster_sectors );
SET_BX( context, free_clusters );
SET_CX( context, sector_bytes );
* INT21_GetDriveAllocInfo
*
*/
-static int INT21_GetDriveAllocInfo( CONTEXT86 *context, int drive )
+static int INT21_GetDriveAllocInfo( CONTEXT86 *context, BYTE drive )
{
INT21_DPB *dpb;
+ drive = INT21_MapDrive( drive );
if (!INT21_FillDrivePB( drive )) return 0;
dpb = &(INT21_GetHeapPointer()->misc_dpb_list[drive]);
SET_AL( context, dpb->cluster_sectors + 1 );
*/
static int INT21_FindFirst( CONTEXT86 *context )
{
- WCHAR *p;
+ WCHAR *p, *q;
const char *path;
FINDFILE_DTA *dta = (FINDFILE_DTA *)INT21_GetCurrentDTA(context);
WCHAR maskW[12], pathW[MAX_PATH];
MultiByteToWideChar(CP_OEMCP, 0, path, -1, pathW, MAX_PATH);
p = strrchrW( pathW, '\\');
+ q = strrchrW( pathW, '/');
+ if (q>p) p = q;
if (!p)
{
if (pathW[0] && pathW[1] == ':') p = pathW + 2;
RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftCreationTime );
RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftLastAccessTime );
RtlSecondsSince1970ToTime( (time_t)0, (LARGE_INTEGER *)&entry->ftLastWriteTime );
- entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL;
+ entry->dwFileAttributes = FA_LABEL;
entry->nFileSizeHigh = entry->nFileSizeLow = 0;
TRACE("returning %s as label\n", debugstr_w(entry->cAlternateFileName));
return 1;
{
BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
FINDFILE_FCB *pFCB;
- DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)INT21_GetCurrentDTA(context);
+ LPBYTE pResult = INT21_GetCurrentDTA(context);
+ DOS_DIRENTRY_LAYOUT *ddl;
WIN32_FIND_DATAW entry;
BYTE attr;
int n;
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)++;
+ *pResult = 0xff;
+ pResult += 6; /* leave reserved field behind */
+ *pResult++ = entry.dwFileAttributes;
}
- *(BYTE *)pResult = INT21_MapDrive( pFCB->drive ); /* DOS_DIRENTRY_LAYOUT after current drive number */
- ((BYTE *)pResult)++;
- pResult->fileattr = entry.dwFileAttributes;
- pResult->cluster = 0; /* what else? */
- pResult->filesize = entry.nFileSizeLow;
- memset( pResult->reserved, 0, sizeof(pResult->reserved) );
+ *pResult++ = INT21_MapDrive( pFCB->drive ); /* DOS_DIRENTRY_LAYOUT after current drive number */
+ ddl = (DOS_DIRENTRY_LAYOUT*)pResult;
+ ddl->fileattr = entry.dwFileAttributes;
+ ddl->cluster = 0; /* what else? */
+ ddl->filesize = entry.nFileSizeLow;
+ memset( ddl->reserved, 0, sizeof(ddl->reserved) );
FileTimeToDosDateTime( &entry.ftLastWriteTime,
- &pResult->filedate, &pResult->filetime );
+ &ddl->filedate, &ddl->filetime );
/* Convert file name to FCB format */
if (entry.cAlternateFileName[0])
INT21_ToDosFCBFormat( entry.cAlternateFileName, nameW );
else
INT21_ToDosFCBFormat( entry.cFileName, nameW );
- WideCharToMultiByte(CP_OEMCP, 0, nameW, 11, pResult->filename, 11, NULL, NULL);
+ WideCharToMultiByte(CP_OEMCP, 0, nameW, 11, ddl->filename, 11, NULL, NULL);
return 1;
}
BOOL bSetDOSExtendedError = FALSE;
TRACE( "AX=%04x BX=%04x CX=%04x DX=%04x "
- "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08lx\n",
+ "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08x\n",
AX_reg(context), BX_reg(context),
CX_reg(context), DX_reg(context),
SI_reg(context), DI_reg(context),
break;
case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
- TRACE("WRITE '$'-terminated string from %04lX:%04X to stdout\n",
+ TRACE("WRITE '$'-terminated string from %04X:%04X to stdout\n",
context->SegDs, DX_reg(context) );
{
LPSTR data = CTX_SEG_OFF_TO_LIN( context,
context->SegDs, context->Edx );
LPSTR p = data;
-
+ DWORD w;
/*
* Do NOT use strchr() to calculate the string length,
* as '\0' is valid string content, too!
if (DOSVM_IsWin16())
WriteFile( DosFileHandleToWin32Handle(1),
- data, p - data, 0, 0 );
+ data, p - data, &w, NULL );
else
for(; data != p; data++)
DOSVM_PutChar( *data );
break;
case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
- TRACE( "SET DISK TRANSFER AREA ADDRESS %04lX:%04X\n",
+ TRACE( "SET DISK TRANSFER AREA ADDRESS %04X:%04X\n",
context->SegDs, DX_reg(context) );
{
TDB *task = GlobalLock16( GetCurrentTask() );
break;
case 0x36: /* GET FREE DISK SPACE */
- TRACE("GET FREE DISK SPACE FOR DRIVE %s\n",
+ TRACE("GET FREE DISK SPACE FOR DRIVE %s (limited to about 1GB)\n",
INT21_DriveName( DL_reg(context) ));
if (!INT21_GetFreeDiskSpace(context)) SET_AX( context, 0xffff );
break;
break;
case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
- TRACE( "READ from %d to %04lX:%04X for %d bytes\n",
+ TRACE( "READ from %d to %04X:%04X for %d bytes\n",
BX_reg(context),
context->SegDs,
DX_reg(context),
/* Some programs pass a count larger than the allocated buffer */
if (DOSVM_IsWin16())
{
- WORD maxcount = GetSelectorLimit16( context->SegDs )
+ DWORD maxcount = GetSelectorLimit16( context->SegDs )
- DX_reg(context) + 1;
if (count > maxcount)
count = maxcount;
break;
case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
- TRACE( "WRITE from %04lX:%04X to handle %d for %d byte\n",
+ TRACE( "WRITE from %04X:%04X to handle %d for %d byte\n",
context->SegDs, DX_reg(context),
BX_reg(context), CX_reg(context) );
{
- BYTE *ptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
+ char *ptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
if (!DOSVM_IsWin16() &&
(BX_reg(context) == 1 || BX_reg(context) == 2))
break;
case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
- TRACE( "LSEEK handle %d offset %ld from %s\n",
+ TRACE( "LSEEK handle %d offset %d from %s\n",
BX_reg(context),
MAKELONG( DX_reg(context), CX_reg(context) ),
(AL_reg(context) == 0) ?
selector = LOWORD( rv );
}
else
- DOSMEM_GetBlock( bytes, &selector );
+ DOSMEM_AllocBlock( bytes, &selector );
if (selector)
{
break;
case 0x49: /* FREE MEMORY */
- TRACE( "FREE MEMORY segment %04lX\n", context->SegEs );
+ TRACE( "FREE MEMORY segment %04X\n", context->SegEs );
{
BOOL ok;
context->SegEs = 0;
}
else
- ok = DOSMEM_FreeBlock( (void*)((DWORD)context->SegEs << 4) );
+ ok = DOSMEM_FreeBlock( PTR_REAL_TO_LIN(context->SegEs, 0) );
if (!ok)
{
break;
case 0x4a: /* RESIZE MEMORY BLOCK */
- TRACE( "RESIZE MEMORY segment %04lX to %d paragraphs\n",
+ TRACE( "RESIZE MEMORY segment %04X to %d paragraphs\n",
context->SegEs, BX_reg(context) );
{
DWORD newsize = (DWORD)BX_reg(context) << 4;
}
else
{
- LPVOID address = (void*)((DWORD)context->SegEs << 4);
+ LPVOID address = (void*)(context->SegEs << 4);
UINT blocksize = DOSMEM_ResizeBlock( address, newsize, FALSE );
RESET_CFLAG(context);
case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
{
- BYTE *program = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
+ char *program = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
BYTE *paramblk = CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx);
TRACE( "EXEC %s\n", program );
/*
* Exit from DPMI.
*/
- DWORD rv = AL_reg(context);
+ ULONG_PTR rv = AL_reg(context);
RaiseException( EXCEPTION_VM86_INTx, 0, 1, &rv );
}
break;
switch (AL_reg(context))
{
case 0x00: /* LOCK */
- TRACE( "lock handle %d offset %ld length %ld\n",
+ TRACE( "lock handle %d offset %d length %d\n",
BX_reg(context), offset, length );
if (!LockFile( handle, offset, 0, length, 0 ))
bSetDOSExtendedError = TRUE;
break;
case 0x01: /* UNLOCK */
- TRACE( "unlock handle %d offset %ld length %ld\n",
+ TRACE( "unlock handle %d offset %d length %d\n",
BX_reg(context), offset, length );
if (!UnlockFile( handle, offset, 0, length, 0 ))
bSetDOSExtendedError = TRUE;
/* Print error code if carry flag is set. */
if (context->EFlags & 0x0001)
- TRACE("failed, error %ld\n", GetLastError() );
+ TRACE("failed, error %d\n", GetLastError() );
TRACE( "returning: AX=%04x BX=%04x CX=%04x DX=%04x "
- "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08lx\n",
+ "SI=%04x DI=%04x DS=%04x ES=%04x EFL=%08x\n",
AX_reg(context), BX_reg(context),
CX_reg(context), DX_reg(context),
SI_reg(context), DI_reg(context),