Changelog: Add prototype for GetCompressedFileSize. Move some int21 functions to winedos. Improve file attribute functions. Index: include/winbase.h =================================================================== RCS file: /home/wine/wine/include/winbase.h,v retrieving revision 1.180 diff -u -r1.180 winbase.h --- include/winbase.h 18 Mar 2003 05:04:34 -0000 1.180 +++ include/winbase.h 29 Mar 2003 20:52:50 -0000 @@ -1300,6 +1300,9 @@ LPSTR WINAPI GetCommandLineA(void); LPWSTR WINAPI GetCommandLineW(void); #define GetCommandLine WINELIB_NAME_AW(GetCommandLine) +DWORD WINAPI GetCompressedFileSizeA(LPCSTR,LPDWORD); +DWORD WINAPI GetCompressedFileSizeW(LPCWSTR,LPDWORD); +#define GetCompressedFileSize WINELIB_NAME_AW(GetCompressedFileSize) BOOL WINAPI GetComputerNameA(LPSTR,LPDWORD); BOOL WINAPI GetComputerNameW(LPWSTR,LPDWORD); #define GetComputerName WINELIB_NAME_AW(GetComputerName) Index: msdos/int21.c =================================================================== RCS file: /home/wine/wine/msdos/int21.c,v retrieving revision 1.90 diff -u -r1.90 int21.c --- msdos/int21.c 22 Mar 2003 21:09:32 -0000 1.90 +++ msdos/int21.c 29 Mar 2003 20:52:52 -0000 @@ -1020,28 +1020,6 @@ if (!INT21_GetFreeDiskSpace(context)) SET_AX( context, 0xffff ); break; - case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */ - 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 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */ TRACE("CHDIR %s\n", (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx)); @@ -1060,69 +1038,6 @@ OpenExistingFile(context); 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; - 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 SET_AX( context, (WORD)result ); - } - 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) bSetDOSExtendedError = TRUE; - else - { - SET_AX( context, LOWORD(status) ); - SET_DX( context, HIWORD(status) ); - } - } - break; - - case 0x43: /* FILE ATTRIBUTES */ - switch (AL_reg(context)) - { - case 0x00: - TRACE("GET FILE ATTRIBUTES for %s\n", - (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx)); - SET_AX( context, GetFileAttributesA( CTX_SEG_OFF_TO_LIN(context, context->SegDs, - context->Edx))); - if (AX_reg(context) == 0xffff) bSetDOSExtendedError = TRUE; - else SET_CX( context, AX_reg(context) ); - break; - - case 0x01: - 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)) { @@ -1334,55 +1249,6 @@ case 0x71: /* MS-DOS 7 (Windows95) - LONG FILENAME FUNCTIONS */ switch(AL_reg(context)) { - case 0x39: /* Create directory */ - 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 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"); - SET_CX( context, 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); - SET_AL( context, 0 ); - break; - } - break; case 0x47: /* Get current directory */ TRACE(" LONG FILENAME - GET CURRENT DIRECTORY for drive %s\n", INT21_DriveName(DL_reg(context))); Index: dlls/winedos/int21.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/int21.c,v retrieving revision 1.26 diff -u -r1.26 int21.c --- dlls/winedos/int21.c 4 Mar 2003 02:15:56 -0000 1.26 +++ dlls/winedos/int21.c 29 Mar 2003 20:52:55 -0000 @@ -43,6 +43,11 @@ */ extern void WINAPI INT_Int21Handler( CONTEXT86 *context ); +/* + * Forward declarations. + */ +static BOOL INT21_RenameFile( CONTEXT86 *context ); + WINE_DEFAULT_DEBUG_CHANNEL(int21); @@ -358,6 +363,49 @@ /*********************************************************************** + * INT21_CreateDirectory + * + * Handler for: + * - function 0x39 + * - subfunction 0x39 of function 0x71 + * - subfunction 0xff of function 0x43 (CL == 0x39) + */ +static BOOL INT21_CreateDirectory( CONTEXT86 *context ) +{ + WCHAR dirW[MAX_PATH]; + char *dirA = CTX_SEG_OFF_TO_LIN(context, + context->SegDs, + context->Edx); + + TRACE( "CREATE DIRECTORY %s\n", dirA ); + + MultiByteToWideChar(CP_OEMCP, 0, dirA, -1, dirW, MAX_PATH); + + if (CreateDirectoryW(dirW, NULL)) + return TRUE; + + /* + * 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 + */ + switch (GetLastError()) + { + case ERROR_ALREADY_EXISTS: + case ERROR_FILENAME_EXCED_RANGE: + case ERROR_DISK_FULL: + SetLastError(ERROR_ACCESS_DENIED); + break; + default: + break; + } + + return FALSE; +} + + +/*********************************************************************** * INT21_ExtendedCountryInformation * * Handler for function 0x65. @@ -479,6 +527,257 @@ /*********************************************************************** + * INT21_FileAttributes + * + * Handler for: + * - function 0x43 + * - subfunction 0x43 of function 0x71 + */ +static BOOL INT21_FileAttributes( CONTEXT86 *context, + BYTE subfunction, + BOOL islong ) +{ + WCHAR fileW[MAX_PATH]; + char *fileA = CTX_SEG_OFF_TO_LIN(context, + context->SegDs, + context->Edx); + HANDLE handle; + BOOL status; + FILETIME filetime; + DWORD result; + WORD date, time; + + switch (subfunction) + { + case 0x00: /* GET FILE ATTRIBUTES */ + TRACE( "GET FILE ATTRIBUTES for %s\n", fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + result = GetFileAttributesW( fileW ); + if (result == -1) + return FALSE; + else + { + SET_CX( context, (WORD)result ); + if (!islong) + SET_AX( context, (WORD)result ); /* DR DOS */ + } + break; + + case 0x01: /* SET FILE ATTRIBUTES */ + TRACE( "SET FILE ATTRIBUTES 0x%02x for %s\n", + CX_reg(context), fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + if (!SetFileAttributesW( fileW, CX_reg(context) )) + return FALSE; + break; + + case 0x02: /* GET COMPRESSED FILE SIZE */ + TRACE( "GET COMPRESSED FILE SIZE for %s\n", fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + result = GetCompressedFileSizeW( fileW, NULL ); + if (result == INVALID_FILE_SIZE) + return FALSE; + else + { + SET_AX( context, LOWORD(result) ); + SET_DX( context, HIWORD(result) ); + } + break; + + case 0x03: /* SET FILE LAST-WRITTEN DATE AND TIME */ + if (!islong) + INT_BARF( context, 0x21 ); + else + { + TRACE( "SET FILE LAST-WRITTEN DATE AND TIME, file %s\n", fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + handle = CreateFileW( fileW, GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + DosDateTimeToFileTime( DI_reg(context), + CX_reg(context), + &filetime ); + status = SetFileTime( handle, NULL, NULL, &filetime ); + + CloseHandle( handle ); + return status; + } + break; + + case 0x04: /* GET FILE LAST-WRITTEN DATE AND TIME */ + if (!islong) + INT_BARF( context, 0x21 ); + else + { + TRACE( "GET FILE LAST-WRITTEN DATE AND TIME, file %s\n", fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + handle = CreateFileW( fileW, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + status = GetFileTime( handle, NULL, NULL, &filetime ); + if (status) + { + FileTimeToDosDateTime( &filetime, &date, &time ); + SET_DI( context, date ); + SET_CX( context, time ); + } + + CloseHandle( handle ); + return status; + } + break; + + case 0x05: /* SET FILE LAST ACCESS DATE */ + if (!islong) + INT_BARF( context, 0x21 ); + else + { + TRACE( "SET FILE LAST ACCESS DATE, file %s\n", fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + handle = CreateFileW( fileW, GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + DosDateTimeToFileTime( DI_reg(context), + 0, + &filetime ); + status = SetFileTime( handle, NULL, &filetime, NULL ); + + CloseHandle( handle ); + return status; + } + break; + + case 0x06: /* GET FILE LAST ACCESS DATE */ + if (!islong) + INT_BARF( context, 0x21 ); + else + { + TRACE( "GET FILE LAST ACCESS DATE, file %s\n", fileA ); + MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + + handle = CreateFileW( fileW, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + status = GetFileTime( handle, NULL, &filetime, NULL ); + if (status) + { + FileTimeToDosDateTime( &filetime, &date, NULL ); + SET_DI( context, date ); + } + + CloseHandle( handle ); + return status; + } + break; + + case 0x07: /* SET FILE CREATION DATE AND TIME */ + if (!islong) + INT_BARF( context, 0x21 ); + else + { + TRACE( "SET FILE CREATION DATE AND TIME, file %s\n", fileA ); + + handle = CreateFileW( fileW, GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + /* + * FIXME: SI has number of 10-millisecond units past time in CX. + */ + DosDateTimeToFileTime( DI_reg(context), + CX_reg(context), + &filetime ); + status = SetFileTime( handle, &filetime, NULL, NULL ); + + CloseHandle( handle ); + return status; + } + break; + + case 0x08: /* GET FILE CREATION DATE AND TIME */ + if (!islong) + INT_BARF( context, 0x21 ); + else + { + TRACE( "GET FILE CREATION DATE AND TIME, handle %d\n", + BX_reg(context) ); + + handle = CreateFileW( fileW, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + status = GetFileTime( handle, &filetime, NULL, NULL ); + if (status) + { + FileTimeToDosDateTime( &filetime, &date, &time ); + SET_DI( context, date ); + SET_CX( context, time ); + /* + * FIXME: SI has number of 10-millisecond units past + * time in CX. + */ + SET_SI( context, 0 ); + } + + CloseHandle(handle); + return status; + } + break; + + case 0xff: /* EXTENDED-LENGTH FILENAME OPERATIONS */ + if (islong || context->Ebp != 0x5053) + INT_BARF( context, 0x21 ); + else + { + switch(CL_reg(context)) + { + case 0x39: + if (!INT21_CreateDirectory( context )) + return FALSE; + break; + + case 0x56: + if (!INT21_RenameFile( context )) + return FALSE; + break; + + default: + INT_BARF( context, 0x21 ); + } + } + break; + + default: + INT_BARF( context, 0x21 ); + } + + return TRUE; +} + + +/*********************************************************************** * INT21_FileDateTime * * Handler for function 0x57. @@ -751,10 +1050,14 @@ switch (AL_reg(context)) { case 0x0d: /* RESET DRIVE */ - case 0x39: /* LONG FILENAME - MAKE DIRECTORY */ INT_Int21Handler( context ); break; + case 0x39: /* LONG FILENAME - MAKE DIRECTORY */ + if (!INT21_CreateDirectory( context )) + bSetDOSExtendedError = TRUE; + break; + case 0x3a: /* LONG FILENAME - REMOVE DIRECTORY */ { WCHAR dirW[MAX_PATH]; @@ -788,6 +1091,10 @@ break; case 0x43: /* LONG FILENAME - EXTENDED GET/SET FILE ATTRIBUTES */ + if (!INT21_FileAttributes( context, BL_reg(context), TRUE )) + bSetDOSExtendedError = TRUE; + break; + case 0x47: /* LONG FILENAME - GET CURRENT DIRECTORY */ case 0x4e: /* LONG FILENAME - FIND FIRST MATCHING FILE */ case 0x4f: /* LONG FILENAME - FIND NEXT MATCHING FILE */ @@ -795,21 +1102,8 @@ break; case 0x56: /* LONG FILENAME - RENAME FILE */ - { - WCHAR fromW[MAX_PATH]; - WCHAR toW[MAX_PATH]; - char *fromA = CTX_SEG_OFF_TO_LIN(context, - context->SegDs,context->Edx); - char *toA = CTX_SEG_OFF_TO_LIN(context, - context->SegEs,context->Edi); - - TRACE( "LONG FILENAME - RENAME FILE %s to %s\n", fromA, toA ); - MultiByteToWideChar(CP_OEMCP, 0, fromA, -1, fromW, MAX_PATH); - MultiByteToWideChar(CP_OEMCP, 0, toA, -1, toW, MAX_PATH); - - if (!MoveFileW( fromW, toW )) - bSetDOSExtendedError = TRUE; - } + if (!INT21_RenameFile(context)) + bSetDOSExtendedError = TRUE; break; case 0x60: /* LONG FILENAME - CONVERT PATH */ @@ -837,6 +1131,31 @@ /*********************************************************************** + * INT21_RenameFile + * + * Handler for: + * - function 0x56 + * - subfunction 0x56 of function 0x71 + * - subfunction 0xff of function 0x43 (CL == 0x56) + */ +static BOOL INT21_RenameFile( CONTEXT86 *context ) +{ + WCHAR fromW[MAX_PATH]; + WCHAR toW[MAX_PATH]; + char *fromA = CTX_SEG_OFF_TO_LIN(context, + context->SegDs,context->Edx); + char *toA = CTX_SEG_OFF_TO_LIN(context, + context->SegEs,context->Edi); + + TRACE( "RENAME FILE %s to %s\n", fromA, toA ); + MultiByteToWideChar(CP_OEMCP, 0, fromA, -1, fromW, MAX_PATH); + MultiByteToWideChar(CP_OEMCP, 0, toA, -1, toW, MAX_PATH); + + return MoveFileW( fromW, toW ); +} + + +/*********************************************************************** * INT21_GetExtendedError */ static void INT21_GetExtendedError( CONTEXT86 *context ) @@ -1349,7 +1668,8 @@ break; case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */ - INT_Int21Handler( context ); + if (!INT21_CreateDirectory( context )) + bSetDOSExtendedError = TRUE; break; case 0x3a: /* "RMDIR" - REMOVE DIRECTORY */ @@ -1380,7 +1700,38 @@ break; case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */ - INT_Int21Handler( context ); + TRACE( "READ from %d to %04lX:%04X for %d bytes\n", + BX_reg(context), + context->SegDs, + DX_reg(context), + CX_reg(context) ); + { + DWORD result; + WORD count = CX_reg(context); + BYTE *buffer = CTX_SEG_OFF_TO_LIN( context, + context->SegDs, + context->Edx ); + + /* Some programs pass a count larger than the allocated buffer */ + if (DOSVM_IsWin16()) + { + WORD maxcount = GetSelectorLimit16( context->SegDs ) + - DX_reg(context) + 1; + if (count > maxcount) + count = maxcount; + } + + /* + * FIXME: Reading from console (BX=1) in DOS mode + * does not work as it is supposed to work. + */ + + if (ReadFile( DosFileHandleToWin32Handle(BX_reg(context)), + buffer, count, &result, NULL )) + SET_AX( context, (WORD)result ); + else + bSetDOSExtendedError = TRUE; + } break; case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */ @@ -1425,8 +1776,30 @@ 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") ); + { + HANDLE handle = DosFileHandleToWin32Handle(BX_reg(context)); + LONG offset = MAKELONG( DX_reg(context), CX_reg(context) ); + DWORD status = SetFilePointer( handle, offset, + NULL, AL_reg(context) ); + if (status == INVALID_SET_FILE_POINTER) + bSetDOSExtendedError = TRUE; + else + { + SET_AX( context, LOWORD(status) ); + SET_DX( context, HIWORD(status) ); + } + } + break; + case 0x43: /* FILE ATTRIBUTES */ - INT_Int21Handler( context ); + if (!INT21_FileAttributes( context, AL_reg(context), FALSE )) + bSetDOSExtendedError = TRUE; break; case 0x44: /* IOCTL */ @@ -1617,21 +1990,8 @@ break; case 0x56: /* "RENAME" - RENAME FILE */ - { - WCHAR fromW[MAX_PATH]; - WCHAR toW[MAX_PATH]; - char *fromA = CTX_SEG_OFF_TO_LIN(context, - context->SegDs,context->Edx); - char *toA = CTX_SEG_OFF_TO_LIN(context, - context->SegEs,context->Edi); - - TRACE( "RENAME %s to %s\n", fromA, toA ); - MultiByteToWideChar(CP_OEMCP, 0, fromA, -1, fromW, MAX_PATH); - MultiByteToWideChar(CP_OEMCP, 0, toA, -1, toW, MAX_PATH); - - if (!MoveFileW( fromW, toW )) - bSetDOSExtendedError = TRUE; - } + if (!INT21_RenameFile( context )) + bSetDOSExtendedError = TRUE; break; case 0x57: /* FILE DATE AND TIME */ -- Jukka Heinonen <http://www.iki.fi/jhei/>