Changelog: Migrate create/open file functions to winedos. Some fixes based on patch by Ferenc Wagner. Index: dlls/winedos/int21.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/int21.c,v retrieving revision 1.37 diff -u -r1.37 int21.c --- dlls/winedos/int21.c 13 Jun 2003 18:05:18 -0000 1.37 +++ dlls/winedos/int21.c 14 Jun 2003 19:06:15 -0000 @@ -519,6 +519,209 @@ /*********************************************************************** + * INT21_CreateFile + * + * Handler for: + * - function 0x3c + * - function 0x3d + * - function 0x5b + * - function 0x6c + * - subfunction 0x6c of function 0x71 + */ +static BOOL INT21_CreateFile( CONTEXT86 *context, + DWORD pathSegOff, + BOOL returnStatus, + WORD dosAccessShare, + BYTE dosAction ) +{ + WORD dosStatus; + char *pathA = CTX_SEG_OFF_TO_LIN(context, context->SegDs, pathSegOff); + WCHAR pathW[MAX_PATH]; + DWORD winAccess; + DWORD winAttributes; + HANDLE winHandle; + DWORD winMode; + DWORD winSharing; + + TRACE( "CreateFile called: function=%02x, action=%02x, access/share=%04x, " + "create flags=%04x, file=%s.\n", + AH_reg(context), dosAction, dosAccessShare, CX_reg(context), pathA ); + + /* + * Application tried to create/open a file whose name + * ends with a backslash. This is not allowed. + * + * FIXME: This needs to be validated, especially the return value. + */ + if (pathA[strlen(pathA) - 1] == '/') + { + SetLastError( ERROR_FILE_NOT_FOUND ); + return FALSE; + } + + /* + * Convert DOS action flags into Win32 creation disposition parameter. + */ + switch(dosAction) + { + case 0x01: + winMode = OPEN_EXISTING; + break; + case 0x02: + winMode = TRUNCATE_EXISTING; + break; + case 0x10: + winMode = CREATE_NEW; + break; + case 0x11: + winMode = OPEN_ALWAYS; + break; + case 0x12: + winMode = CREATE_ALWAYS; + break; + default: + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + /* + * Convert DOS access/share flags into Win32 desired access parameter. + */ + switch(dosAccessShare & 0x07) + { + case OF_READ: + winAccess = GENERIC_READ; + break; + case OF_WRITE: + winAccess = GENERIC_WRITE; + break; + case OF_READWRITE: + winAccess = GENERIC_READ | GENERIC_WRITE; + break; + case 0x04: + /* + * Read-only, do not modify file's last-access time (DOS7). + * + * FIXME: How to prevent modification of last-access time? + */ + winAccess = GENERIC_READ; + break; + default: + winAccess = 0; + } + + /* + * Convert DOS access/share flags into Win32 share mode parameter. + */ + switch(dosAccessShare & 0x70) + { + case OF_SHARE_EXCLUSIVE: + winSharing = 0; + break; + case OF_SHARE_DENY_WRITE: + winSharing = FILE_SHARE_READ; + break; + case OF_SHARE_DENY_READ: + winSharing = FILE_SHARE_WRITE; + break; + case OF_SHARE_DENY_NONE: + case OF_SHARE_COMPAT: + default: + winSharing = FILE_SHARE_READ | FILE_SHARE_WRITE; + } + + /* + * FIXME: Bit (dosAccessShare & 0x80) represents inheritance. + * What to do with this bit? + * FIXME: Bits in the high byte of dosAccessShare are not supported. + * See both function 0x6c and subfunction 0x6c of function 0x71 for + * definition of these bits. + */ + + /* + * Convert DOS create attributes into Win32 flags and attributes parameter. + */ + if (winMode == OPEN_EXISTING || winMode == TRUNCATE_EXISTING) + { + winAttributes = 0; + } + else + { + WORD dosAttributes = CX_reg(context); + + if (dosAttributes & FILE_ATTRIBUTE_LABEL) + { + /* + * Application tried to create volume label entry. + * This is difficult to support so we do not allow it. + * + * FIXME: If volume does not already have a label, + * this function is supposed to succeed. + */ + SetLastError( ERROR_ACCESS_DENIED ); + return TRUE; + } + + winAttributes = dosAttributes & + (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE); + } + + /* + * Open the file. + */ + MultiByteToWideChar(CP_OEMCP, 0, pathA, -1, pathW, MAX_PATH); + + winHandle = CreateFileW( pathW, winAccess, winSharing, NULL, + winMode, winAttributes, 0 ); + + if (winHandle == INVALID_HANDLE_VALUE) + return FALSE; + + /* + * Determine DOS file status. + * + * 1 = file opened + * 2 = file created + * 3 = file replaced + */ + switch(winMode) + { + case OPEN_EXISTING: + dosStatus = 1; + break; + case TRUNCATE_EXISTING: + dosStatus = 3; + break; + case CREATE_NEW: + dosStatus = 2; + break; + case OPEN_ALWAYS: + dosStatus = (GetLastError() == ERROR_ALREADY_EXISTS) ? 1 : 2; + break; + case CREATE_ALWAYS: + dosStatus = (GetLastError() == ERROR_ALREADY_EXISTS) ? 3 : 2; + break; + default: + dosStatus = 0; + } + + /* + * Return DOS file handle and DOS status. + */ + SET_AX( context, Win32HandleToDosFileHandle(winHandle) ); + + if (returnStatus) + SET_CX( context, dosStatus ); + + TRACE( "CreateFile finished: handle=%d, status=%d.\n", + AX_reg(context), dosStatus ); + + return TRUE; +} + + +/*********************************************************************** * INT21_BufferedInput * * Handler for function 0x0a and reading from console using @@ -2156,7 +2359,15 @@ break; case 0x60: /* LONG FILENAME - CONVERT PATH */ + INT_Int21Handler( context ); + break; + case 0x6c: /* LONG FILENAME - CREATE OR OPEN FILE */ + if (!INT21_CreateFile( context, context->Esi, TRUE, + BX_reg(context), DL_reg(context) )) + bSetDOSExtendedError = TRUE; + break; + case 0xa0: /* LONG FILENAME - GET VOLUME INFORMATION */ case 0xa1: /* LONG FILENAME - "FindClose" - TERMINATE DIRECTORY SEARCH */ INT_Int21Handler( context ); @@ -2917,8 +3128,15 @@ break; case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */ + if (!INT21_CreateFile( context, context->Edx, FALSE, + OF_READWRITE | OF_SHARE_COMPAT, 0x12 )) + bSetDOSExtendedError = TRUE; + break; + case 0x3d: /* "OPEN" - OPEN EXISTING FILE */ - INT_Int21Handler( context ); + if (!INT21_CreateFile( context, context->Edx, FALSE, + AL_reg(context), 0x01 )) + bSetDOSExtendedError = TRUE; break; case 0x3e: /* "CLOSE" - CLOSE FILE */ @@ -3267,10 +3485,15 @@ break; case 0x5a: /* CREATE TEMPORARY FILE */ - case 0x5b: /* CREATE NEW FILE */ INT_Int21Handler( context ); break; + case 0x5b: /* CREATE NEW FILE */ + if (!INT21_CreateFile( context, context->Edx, FALSE, + OF_READWRITE | OF_SHARE_COMPAT, 0x10 )) + bSetDOSExtendedError = TRUE; + break; + case 0x5c: /* "FLOCK" - RECORD LOCKING */ { DWORD offset = MAKELONG(DX_reg(context), CX_reg(context)); @@ -3381,7 +3604,9 @@ break; case 0x6c: /* EXTENDED OPEN/CREATE */ - INT_Int21Handler( context ); + if (!INT21_CreateFile( context, context->Esi, TRUE, + BX_reg(context), DL_reg(context) )) + bSetDOSExtendedError = TRUE; break; case 0x70: /* MSDOS 7 - GET/SET INTERNATIONALIZATION INFORMATION */ Index: msdos/int21.c =================================================================== RCS file: /home/wine/wine/msdos/int21.c,v retrieving revision 1.95 diff -u -r1.95 int21.c --- msdos/int21.c 13 Jun 2003 18:05:18 -0000 1.95 +++ msdos/int21.c 14 Jun 2003 19:06:17 -0000 @@ -411,12 +411,6 @@ } return drivestring; } -static BOOL INT21_CreateFile( CONTEXT86 *context ) -{ - SET_AX( context, _lcreat16( CTX_SEG_OFF_TO_LIN(context, context->SegDs, - context->Edx ), CX_reg(context) ) ); - return (AX_reg(context) == (WORD)HFILE_ERROR16); -} static HFILE16 _lcreat16_uniq( LPCSTR path, INT attr ) { @@ -427,110 +421,6 @@ CREATE_NEW, attr, 0 )); } -static void OpenExistingFile( CONTEXT86 *context ) -{ - SET_AX( context, _lopen16( CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx), - AL_reg(context) )); - if (AX_reg(context) == (WORD)HFILE_ERROR16) - { - SET_AX( context, GetLastError() ); - SET_CFLAG(context); - } -} - -static BOOL INT21_ExtendedOpenCreateFile(CONTEXT86 *context ) -{ - BOOL bExtendedError = FALSE; - BYTE action = DL_reg(context); - - /* Shuffle arguments to call OpenExistingFile */ - SET_AL( context, BL_reg(context) ); - SET_DX( context, SI_reg(context) ); - /* BX,CX and DX should be preserved */ - OpenExistingFile(context); - - if ((context->EFlags & 0x0001) == 0) /* File exists */ - { - UINT16 uReturnCX = 0; - - /* Now decide what do do */ - - if ((action & 0x07) == 0) - { - _lclose16( AX_reg(context) ); - SET_AX( 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"); - SET_AX( context, 0x000C ); /*Access code invalid*/ - SET_CFLAG(context); - } - else - { - TRACE("extended open/create: Closing before truncate\n"); - if (_lclose16( AX_reg(context) )) - { - WARN("extended open/create: close before trunc failed\n"); - SET_AX( context, 0x0019 ); /*Seek Error*/ - SET_CX( context, 0 ); - SET_CFLAG(context); - } - /* Shuffle arguments to call CreateFile */ - - TRACE("extended open/create: Truncating\n"); - SET_AL( context, BL_reg(context) ); - /* CX is still the same */ - SET_DX( 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; - } - } - else uReturnCX = 0x1; - - SET_CX( context, uReturnCX ); - } - else /* file does not exist */ - { - RESET_CFLAG(context); /* was set by OpenExistingFile(context) */ - if ((action & 0xF0)== 0) - { - SET_CX( context, 0 ); - SET_CFLAG(context); - WARN("extended open/create: failed, file dosen't exist\n"); - } - else - { - /* Shuffle arguments to call CreateFile */ - TRACE("extended open/create: Creating\n"); - SET_AL( context, BL_reg(context) ); - /* CX should still be the same */ - SET_DX( 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; - } - SET_CX( context, 2 ); - } - } - - return bExtendedError; -} - static int INT21_FindFirst( CONTEXT86 *context ) { @@ -858,18 +748,6 @@ if (!INT21_GetFreeDiskSpace(context)) SET_AX( context, 0xffff ); break; - case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */ - 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 0x44: /* IOCTL */ switch (AL_reg(context)) { @@ -917,15 +795,6 @@ bSetDOSExtendedError = !INT21_CreateTempFile(context); break; - case 0x5b: /* CREATE NEW FILE */ - TRACE("CREATE NEW FILE 0x%02x for %s\n", CX_reg(context), - (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx)); - SET_AX( context, - _lcreat16_uniq( CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx), - CX_reg(context) )); - bSetDOSExtendedError = (AX_reg(context) != 0); - break; - case 0x5e: bSetDOSExtendedError = INT21_networkfunc (context); break; @@ -992,12 +861,6 @@ } break; - case 0x6C: /* Extended Open/Create*/ - 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 */ switch(AL_reg(context)) { @@ -1074,12 +937,6 @@ 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; default: FIXME("Unimplemented long file name function:\n"); -- Jukka Heinonen <http://www.iki.fi/jhei/>