From 8ca6cadab1ebb386f1dfa2e47c609ba5f43cc394 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 14 Nov 2003 04:54:39 +0000 Subject: [PATCH] - moved the remaining of int21 calls to dlls/winedos - disabled drive enabling/disabling as well as disk serial number writing (for DLL separation issues) - added volume management prototypes to include/winbase.h - started DefineDosDevice (needed by first item in this list) - removed int21 specific code from dlls/kernel --- dlls/kernel/Makefile.in | 1 - dlls/kernel/kernel32.spec | 3 +- dlls/winedos/int21.c | 991 ++++++++++++++++++++++++++++++++++++-- files/dos_fs.c | 153 ------ files/drive.c | 59 ++- include/drive.h | 1 - include/file.h | 3 - include/msdos.h | 4 +- include/winbase.h | 39 ++ msdos/int21.c | 837 -------------------------------- 10 files changed, 1039 insertions(+), 1052 deletions(-) delete mode 100644 msdos/int21.c diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in index da3934ffd1a..cb5eceaedda 100644 --- a/dlls/kernel/Makefile.in +++ b/dlls/kernel/Makefile.in @@ -26,7 +26,6 @@ C_SRCS = \ $(TOPOBJDIR)/misc/options.c \ $(TOPOBJDIR)/misc/registry.c \ $(TOPOBJDIR)/msdos/dpmi.c \ - $(TOPOBJDIR)/msdos/int21.c \ atom.c \ change.c \ comm.c \ diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec index 94ddbb79279..59a3a47fd47 100644 --- a/dlls/kernel/kernel32.spec +++ b/dlls/kernel/kernel32.spec @@ -221,7 +221,7 @@ @ stdcall DebugActiveProcess(long) @ stdcall DebugBreak() @ stdcall DefineDosDeviceA(long str str) -@ stub DefineDosDeviceW +@ stdcall DefineDosDeviceW(long wstr wstr) @ stub DelayLoadFailureHook @ stdcall DeleteAtom(long) @ stdcall DeleteCriticalSection(ptr) ntdll.RtlDeleteCriticalSection @@ -1150,7 +1150,6 @@ @ cdecl DOSMEM_ResizeBlock(ptr long long) @ cdecl DRIVE_OpenDevice(long long) @ cdecl FILE_Dup2(long long) -@ stdcall INT_Int21Handler(ptr) @ cdecl LOCAL_Alloc(long long long) @ cdecl LOCAL_Compact(long long long) @ cdecl LOCAL_CountFree(long) diff --git a/dlls/winedos/int21.c b/dlls/winedos/int21.c index 69c3f49cb26..f56dd739655 100644 --- a/dlls/winedos/int21.c +++ b/dlls/winedos/int21.c @@ -26,6 +26,10 @@ #include "config.h" #include +#include +#ifdef HAVE_UNISTD_H +# include +#endif #include "windef.h" #include "winbase.h" @@ -44,9 +48,15 @@ #include "wine/exception.h" /* - * FIXME: Delete this reference when all int21 code has been moved to winedos. + * 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 + * (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) */ -extern void WINAPI INT_Int21Handler( CONTEXT86 *context ); /* * Forward declarations. @@ -161,13 +171,32 @@ struct XFCB { #include "poppack.h" +/* Many calls translate a drive argument like this: + drive number (00h = default, 01h = A:, etc) + */ +/****************************************************************** + * INT21_DriveName + * + * Many calls translate a drive argument like this: + * drive number (00h = default, 01h = A:, etc) + */ +static const char *INT21_DriveName(int drive) +{ + if (drive > 0) + { + if (drive <= 26) return wine_dbg_sprintf("%c:", 'A' + drive - 1); + else return wine_dbg_sprintf( "", drive); + } + return "default"; +} + /*********************************************************************** * INT21_GetCurrentDrive * * Return current drive using scheme (0=A:, 1=B:, 2=C:, ...) or * MAX_DOS_DRIVES on error. */ -static BYTE INT21_GetCurrentDrive() +static BYTE INT21_GetCurrentDrive(void) { WCHAR current_directory[MAX_PATH]; @@ -2092,6 +2121,51 @@ static void INT21_GetPSP( CONTEXT86 *context ) SET_BX( context, DOSVM_psp ); } +static void CreateBPB(int drive, BYTE *data, BOOL16 limited) +/* limited == TRUE is used with INT 0x21/0x440d */ +{ + /* FIXME: we're forcing some values without checking that those are valid */ + 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); + } + } +} /*********************************************************************** * INT21_Ioctl_Block @@ -2176,7 +2250,25 @@ static void INT21_Ioctl_Block( CONTEXT86 *context ) break; case 0x0860: /* get device parameters */ - INT_Int21Handler( context ); + /* FIXME: we're faking some values here */ + /* 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 */ + } + CreateBPB(drive, &dataptr[7], TRUE); + RESET_CFLAG(context); break; case 0x0861: /* read logical device track */ @@ -2198,7 +2290,17 @@ static void INT21_Ioctl_Block( CONTEXT86 *context ) break; case 0x0866: /* get volume serial number */ - INT_Int21Handler( context ); + { + WCHAR label[12],fsname[9]; + DWORD serial; + + drivespec[0] += drive; + 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); + } break; case 0x086a: /* unlock logical volume */ @@ -2207,11 +2309,16 @@ static void INT21_Ioctl_Block( CONTEXT86 *context ) break; case 0x086f: /* get drive map information */ - INT_Int21Handler( context ); + 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 0x0872: - INT_Int21Handler( context ); + /* Trail on error implementation */ + SET_AX( context, drivetype == DRIVE_UNKNOWN ? 0x0f : 0x01 ); + SET_CFLAG(context); /* Seems to be set all the time */ break; default: @@ -2227,7 +2334,19 @@ static void INT21_Ioctl_Block( CONTEXT86 *context ) break; case 0x0f: /* SET LOGICAL DRIVE MAP */ - INT_Int21Handler( context ); + { + 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 */ + } + } break; case 0x11: /* QUERY GENERIC IOCTL CAPABILITY */ @@ -2530,6 +2649,20 @@ static BOOL INT21_Fat32( CONTEXT86 *context ) return TRUE; } +static void INT21_ConvertFindDataWtoA(WIN32_FIND_DATAA *dataA, + const WIN32_FIND_DATAW *dataW) +{ + dataA->dwFileAttributes = dataW->dwFileAttributes; + dataA->ftCreationTime = dataW->ftCreationTime; + dataA->ftLastAccessTime = dataW->ftLastAccessTime; + dataA->ftLastWriteTime = dataW->ftLastWriteTime; + dataA->nFileSizeHigh = dataW->nFileSizeHigh; + dataA->nFileSizeLow = dataW->nFileSizeLow; + WideCharToMultiByte( CP_OEMCP, 0, dataW->cFileName, -1, + dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL ); + WideCharToMultiByte( CP_OEMCP, 0, dataW->cAlternateFileName, -1, + dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL ); +} /*********************************************************************** * INT21_LongFilename @@ -2539,6 +2672,8 @@ static BOOL INT21_Fat32( CONTEXT86 *context ) static void INT21_LongFilename( CONTEXT86 *context ) { BOOL bSetDOSExtendedError = FALSE; + WCHAR pathW[MAX_PATH]; + char* pathA; if (HIBYTE(HIWORD(GetVersion16())) < 0x07) { @@ -2560,17 +2695,11 @@ static void INT21_LongFilename( CONTEXT86 *context ) break; case 0x3a: /* LONG FILENAME - REMOVE DIRECTORY */ - { - WCHAR dirW[MAX_PATH]; - char *dirA = CTX_SEG_OFF_TO_LIN(context, - context->SegDs, context->Edx); + pathA = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); - TRACE( "LONG FILENAME - REMOVE DIRECTORY %s\n", dirA ); - MultiByteToWideChar(CP_OEMCP, 0, dirA, -1, dirW, MAX_PATH); - - if (!RemoveDirectoryW( dirW )) - bSetDOSExtendedError = TRUE; - } + TRACE( "LONG FILENAME - REMOVE DIRECTORY %s\n", pathA); + MultiByteToWideChar(CP_OEMCP, 0, pathA, -1, pathW, MAX_PATH); + if (!RemoveDirectoryW( pathW )) bSetDOSExtendedError = TRUE; break; case 0x3b: /* LONG FILENAME - CHANGE DIRECTORY */ @@ -2579,17 +2708,12 @@ static void INT21_LongFilename( CONTEXT86 *context ) break; case 0x41: /* LONG FILENAME - DELETE FILE */ - { - WCHAR fileW[MAX_PATH]; - char *fileA = CTX_SEG_OFF_TO_LIN(context, - context->SegDs, context->Edx); + pathA = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); - TRACE( "LONG FILENAME - DELETE FILE %s\n", fileA ); - MultiByteToWideChar(CP_OEMCP, 0, fileA, -1, fileW, MAX_PATH); + TRACE( "LONG FILENAME - DELETE FILE %s\n", pathA ); + MultiByteToWideChar(CP_OEMCP, 0, pathA, -1, pathW, MAX_PATH); - if (!DeleteFileW( fileW )) - bSetDOSExtendedError = TRUE; - } + if (!DeleteFileW( pathW )) bSetDOSExtendedError = TRUE; break; case 0x43: /* LONG FILENAME - EXTENDED GET/SET FILE ATTRIBUTES */ @@ -2603,8 +2727,63 @@ static void INT21_LongFilename( CONTEXT86 *context ) break; case 0x4e: /* LONG FILENAME - FIND FIRST MATCHING FILE */ + { + HANDLE handle; + HGLOBAL16 h16; + WIN32_FIND_DATAW dataW; + WIN32_FIND_DATAA* dataA; + + pathA = CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx); + TRACE(" LONG FILENAME - FIND FIRST MATCHING FILE for %s\n", pathA); + + MultiByteToWideChar(CP_OEMCP, 0, pathA, -1, pathW, MAX_PATH); + handle = FindFirstFileW(pathW, &dataW); + + dataA = (WIN32_FIND_DATAA *)CTX_SEG_OFF_TO_LIN(context, context->SegEs, + context->Edi); + if (handle != INVALID_HANDLE_VALUE && + (h16 = GlobalAlloc16(GMEM_MOVEABLE, sizeof(handle)))) + { + HANDLE* ptr = GlobalLock16( h16 ); + *ptr = handle; + GlobalUnlock16( h16 ); + SET_AX( context, h16 ); + INT21_ConvertFindDataWtoA(dataA, &dataW); + } + else + { + if (handle != INVALID_HANDLE_VALUE) FindClose(handle); + SET_AX( context, INVALID_HANDLE_VALUE16); + bSetDOSExtendedError = TRUE; + } + } + break; + case 0x4f: /* LONG FILENAME - FIND NEXT MATCHING FILE */ - INT_Int21Handler( context ); + { + HGLOBAL16 h16 = BX_reg(context); + HANDLE* ptr; + WIN32_FIND_DATAW dataW; + WIN32_FIND_DATAA* dataA; + + TRACE("LONG FILENAME - FIND NEXT MATCHING FILE for handle %d\n", + BX_reg(context)); + + dataA = (WIN32_FIND_DATAA *)CTX_SEG_OFF_TO_LIN(context, context->SegEs, + context->Edi); + + if (h16 != INVALID_HANDLE_VALUE16 && (ptr = GlobalLock16( h16 ))) + { + if (!FindNextFileW(*ptr, &dataW)) bSetDOSExtendedError = TRUE; + else INT21_ConvertFindDataWtoA(dataA, &dataW); + GlobalUnlock16( h16 ); + } + else + { + SetLastError( ERROR_INVALID_HANDLE ); + bSetDOSExtendedError = TRUE; + } + } break; case 0x56: /* LONG FILENAME - RENAME FILE */ @@ -2613,7 +2792,44 @@ static void INT21_LongFilename( CONTEXT86 *context ) break; case 0x60: /* LONG FILENAME - CONVERT PATH */ - INT_Int21Handler( context ); + { + WCHAR res[MAX_PATH]; + + switch (CL_reg(context)) + { + 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)) + bSetDOSExtendedError = TRUE; + else + { + SET_AX( context, 0 ); + WideCharToMultiByte(CP_OEMCP, 0, res, -1, + CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi), + 67, NULL, NULL); + } + break; + + case 0x02: /* Get canonical long filename or path */ + MultiByteToWideChar(CP_OEMCP, 0, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi), -1, pathW, MAX_PATH); + if (!GetFullPathNameW(pathW, 128, res, NULL)) + bSetDOSExtendedError = TRUE; + else + { + SET_AX( context, 0 ); + WideCharToMultiByte(CP_OEMCP, 0, res, -1, + CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi), + 128, NULL, NULL); + } + break; + default: + FIXME("Unimplemented long file name function:\n"); + INT_BARF( context, 0x21 ); + SET_CFLAG(context); + SET_AL( context, 0 ); + break; + } + } break; case 0x6c: /* LONG FILENAME - CREATE OR OPEN FILE */ @@ -2623,10 +2839,52 @@ static void INT21_LongFilename( CONTEXT86 *context ) break; case 0xa0: /* LONG FILENAME - GET VOLUME INFORMATION */ - case 0xa1: /* LONG FILENAME - "FindClose" - TERMINATE DIRECTORY SEARCH */ - INT_Int21Handler( context ); + { + DWORD filename_len, flags; + WCHAR dstW[8]; + + pathA = CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx); + + TRACE("LONG FILENAME - GET VOLUME INFORMATION for drive having root dir '%s'.\n", pathA); + SET_AX( context, 0 ); + MultiByteToWideChar(CP_OEMCP, 0, pathA, -1, pathW, MAX_PATH); + if (!GetVolumeInformationW( pathW, NULL, 0, NULL, &filename_len, + &flags, dstW, 8 )) + { + INT_BARF( context, 0x21 ); + SET_CFLAG(context); + break; + } + SET_BX( context, flags | 0x4000 ); /* support for LFN functions */ + SET_CX( context, filename_len ); + SET_DX( context, MAX_PATH ); /* FIXME: which len if DRIVE_SHORT_NAMES ? */ + WideCharToMultiByte(CP_OEMCP, 0, dstW, -1, + CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi), + 8, NULL, NULL); + } break; + case 0xa1: /* LONG FILENAME - "FindClose" - TERMINATE DIRECTORY SEARCH */ + { + HGLOBAL16 h16 = BX_reg(context); + HANDLE* ptr; + + TRACE("LONG FILENAME - FINDCLOSE for handle %d\n", + BX_reg(context)); + if (h16 != INVALID_HANDLE_VALUE16 && (ptr = GlobalLock16( h16 ))) + { + if (!FindClose( *ptr )) bSetDOSExtendedError = TRUE; + GlobalUnlock16( h16 ); + GlobalFree16( h16 ); + } + else + { + SetLastError( ERROR_INVALID_HANDLE ); + bSetDOSExtendedError = TRUE; + } + } + break; + case 0xa6: /* LONG FILENAME - GET FILE INFO BY HANDLE */ { HANDLE handle = DosFileHandleToWin32Handle(BX_reg(context)); @@ -2692,7 +2950,11 @@ static void INT21_LongFilename( CONTEXT86 *context ) case 0xa9: /* LONG FILENAME - SERVER CREATE OR OPEN FILE */ case 0xaa: /* LONG FILENAME - SUBST */ default: + FIXME("Unimplemented long file name function:\n"); INT_BARF( context, 0x21 ); + SET_CFLAG(context); + SET_AL( context, 0 ); + break; } if (bSetDOSExtendedError) @@ -2728,6 +2990,134 @@ static BOOL INT21_RenameFile( CONTEXT86 *context ) } +/*********************************************************************** + * INT21_NetworkFunc + * + * Handler for: + * - function 0x5e + */ +static BOOL INT21_NetworkFunc (CONTEXT86 *context) +{ + switch (AL_reg(context)) + { + case 0x00: /* Get machine name. */ + { + WCHAR dstW[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD s = sizeof(dstW) / sizeof(WCHAR); + int len; + + char *dst = CTX_SEG_OFF_TO_LIN (context,context->SegDs,context->Edx); + TRACE("getting machine name to %p\n", dst); + if (!GetComputerNameW(dstW, &s) || + !WideCharToMultiByte(CP_OEMCP, 0, dstW, -1, dst, 16, NULL, NULL)) + { + WARN("failed!\n"); + SetLastError( ER_NoNetwork ); + return TRUE; + } + for (len = strlen(dst); len < 15; len++) dst[len] = ' '; + dst[15] = 0; + SET_CH( context, 1 ); /* Valid */ + SET_CL( context, 1 ); /* NETbios number??? */ + TRACE("returning %s\n", debugstr_an(dst, 16)); + return FALSE; + } + + default: + SetLastError( ER_NoNetwork ); + return TRUE; + } +} + +/****************************************************************** + * INT21_GetDiskSerialNumber + * + */ +static int INT21_GetDiskSerialNumber( CONTEXT86 *context ) +{ + BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); + WCHAR path[] = {'A',':',0}, label[11]; + DWORD serial; + + path[0] += INT21_MapDrive(BL_reg(context)); + if (!GetVolumeInformationW( path, label, 11, &serial, NULL, NULL, NULL, 0)) + { + SetLastError( ERROR_INVALID_DRIVE ); + return 0; + } + + *(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); + return 1; +} + + +/****************************************************************** + * INT21_SetDiskSerialNumber + * + */ +static int INT21_SetDiskSerialNumber( CONTEXT86 *context ) +{ +#if 0 + BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); + int drive = INT21_MapDrive(BL_reg(context)); + + if (!is_valid_drive(drive)) + { + SetLastError( ERROR_INVALID_DRIVE ); + return 0; + } + + DRIVE_SetSerialNumber( drive, *(DWORD *)(dataptr + 2) ); + return 1; +#else + FIXME("Setting drive serial number is no longer supported\n"); + SetLastError( ERROR_NOT_SUPPORTED ); + return 0; +#endif +} + + +/****************************************************************** + * INT21_GetFreeDiskSpace + * + */ +static int INT21_GetFreeDiskSpace( CONTEXT86 *context ) +{ + DWORD cluster_sectors, sector_bytes, free_clusters, total_clusters; + WCHAR root[] = {'A',':','\\',0}; + + root[0] += INT21_MapDrive(BL_reg(context)); + if (!GetDiskFreeSpaceW( root, &cluster_sectors, §or_bytes, + &free_clusters, &total_clusters )) return 0; + SET_AX( context, cluster_sectors ); + SET_BX( context, free_clusters ); + SET_CX( context, sector_bytes ); + SET_DX( context, total_clusters ); + return 1; +} + +/****************************************************************** + * INT21_GetDriveAllocInfo + * + */ +static int INT21_GetDriveAllocInfo( CONTEXT86 *context, int drive ) +{ + INT21_DPB *dpb; + + if (!INT21_FillDrivePB( drive )) return 0; + dpb = &(INT21_GetHeapPointer()->misc_dpb_list[drive]); + SET_AL( context, dpb->cluster_sectors + 1 ); + SET_CX( context, dpb->sector_bytes ); + SET_DX( context, dpb->num_clusters1 ); + + context->SegDs = INT21_GetHeapSelector( context ); + SET_BX( context, offsetof( INT21_HEAP, misc_dpb_list[drive].media_ID ) ); + return 1; +} + /*********************************************************************** * INT21_GetExtendedError */ @@ -2843,6 +3233,453 @@ static void INT21_GetExtendedError( CONTEXT86 *context ) SET_CH( context, locus ); } +static BOOL INT21_CreateTempFile( CONTEXT86 *context ) +{ + static int counter = 0; + 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; + + SET_AX( context, + Win32HandleToDosFileHandle( + CreateFileA( name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CREATE_NEW, 0, 0 ) ) ); + if (AX_reg(context) != HFILE_ERROR16) + { + TRACE("created %s\n", name ); + return TRUE; + } + if (GetLastError() != ERROR_FILE_EXISTS) return FALSE; + } +} + +/*********************************************************************** + * DOSFS_ToDosFCBFormat + * + * Convert a file name to DOS FCB format (8+3 chars, padded with blanks), + * expanding wild cards and converting to upper-case in the process. + * File name can be terminated by '\0', '\\' or '/'. + * Return FALSE if the name is not a valid DOS name. + * 'buffer' must be at least 12 characters long. + */ +/* Chars we don't want to see in DOS file names */ +#define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345" +static BOOL INT21_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer ) +{ + static const char invalid_chars[] = INVALID_DOS_CHARS; + LPCWSTR p = name; + int i; + + /* Check for "." and ".." */ + if (*p == '.') + { + p++; + buffer[0] = '.'; + for(i = 1; i < 11; i++) buffer[i] = ' '; + buffer[11] = 0; + if (*p == '.') + { + buffer[1] = '.'; + p++; + } + return (!*p || (*p == '/') || (*p == '\\')); + } + + for (i = 0; i < 8; i++) + { + switch(*p) + { + case '\0': + case '\\': + case '/': + case '.': + buffer[i] = ' '; + break; + case '?': + p++; + /* fall through */ + case '*': + buffer[i] = '?'; + break; + default: + if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE; + buffer[i] = toupperW(*p); + p++; + break; + } + } + + if (*p == '*') + { + /* Skip all chars after wildcard up to first dot */ + while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++; + } + else + { + /* Check if name too long */ + if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE; + } + if (*p == '.') p++; /* Skip dot */ + + for (i = 8; i < 11; i++) + { + switch(*p) + { + case '\0': + case '\\': + case '/': + buffer[i] = ' '; + break; + case '.': + return FALSE; /* Second extension not allowed */ + case '?': + p++; + /* fall through */ + case '*': + buffer[i] = '?'; + break; + default: + if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE; + buffer[i] = toupperW(*p); + p++; + break; + } + } + buffer[11] = '\0'; + + /* at most 3 character of the extension are processed + * is something behind this ? + */ + while (*p == '*' || *p == ' ') p++; /* skip wildcards and spaces */ + return IS_END_OF_NAME(*p); +} + +static HANDLE INT21_FindHandle; +static const WCHAR *INT21_FindPath; /* will point to current dta->fullPath search */ + +/****************************************************************** + * INT21_FindFirst + */ +static int INT21_FindFirst( CONTEXT86 *context ) +{ + WCHAR *p; + const char *path; + FINDFILE_DTA *dta = (FINDFILE_DTA *)INT21_GetCurrentDTA(context); + WCHAR maskW[12], pathW[MAX_PATH]; + DWORD attr; + + path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); + MultiByteToWideChar(CP_OEMCP, 0, path, -1, pathW, MAX_PATH); + + dta->fullPath = HeapAlloc( GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) ); + p = strrchrW(pathW, '/'); + if (p) *p = '\0'; + GetLongPathNameW(pathW, dta->fullPath, MAX_PATH); + if (p) *p = '/'; + attr = GetFileAttributesW(dta->fullPath); + if (attr == 0xffffffff || !(attr & FILE_ATTRIBUTE_DIRECTORY)) + { + SET_AX( context, GetLastError() ); + SET_CFLAG(context); + return 0; + } + + /* Note: terminating NULL in dta->mask overwrites dta->search_attr + * (doesn't matter as it is set below anyway) + */ + if (!INT21_ToDosFCBFormat( p, maskW )) + { + HeapFree( GetProcessHeap(), 0, dta->fullPath ); + dta->fullPath = NULL; + SetLastError( ERROR_FILE_NOT_FOUND ); + SET_AX( context, ERROR_FILE_NOT_FOUND ); + SET_CFLAG(context); + return 0; + } + WideCharToMultiByte(CP_OEMCP, 0, maskW, 12, dta->mask, sizeof(dta->mask), NULL, NULL); + /* we must have a fully qualified file name in dta->fullPath + * (we could have a UNC path, but this would lead to some errors later on) + */ + dta->drive = toupperW(dta->fullPath[0]) - 'A'; + dta->count = 0; + dta->search_attr = CL_reg(context); + return 1; +} + +/****************************************************************** + * match_short + * + * Check is a short path name (DTA unicode) matches a mask (FCB ansi) + */ +static BOOL match_short(LPCWSTR shortW, LPCSTR maskA) +{ + WCHAR mask[12]; + int i, j; + + MultiByteToWideChar(CP_OEMCP, 0, maskA, 12, mask, 12); + + for (i = j = 0; i < 8; i++) + { + switch (mask[i]) + { + case '?': + if (shortW[j] == '\0' || shortW[j] == '.') return FALSE; + j++; + break; + case ' ': if (shortW[j] != '.') return FALSE; break; + default: if (shortW[j++] != mask[i]) return FALSE; break; + } + } + for (i = 8; i < 11; i++) + { + switch (mask[i]) + { + case '?': if (shortW[j++] == '\0') return FALSE; break; + case ' ': if (shortW[j] != '\0') return FALSE; break; + default: if (shortW[j++] != mask[i]) return FALSE; break; + } + } + return TRUE; +} + +static unsigned INT21_FindHelper(LPCWSTR fullPath, unsigned drive, unsigned count, + LPCSTR mask, unsigned search_attr, + WIN32_FIND_DATAW* entry) +{ + unsigned ncalls; + + if ((search_attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL) + { + WCHAR path[] = {' ',':',0}; + + if (count) return 0; + path[0] = drive + 'A'; + if (!GetVolumeInformationW(path, entry->cAlternateFileName, 13, NULL, NULL, NULL, NULL, 0)) return 0; + 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->nFileSizeHigh = entry->nFileSizeLow = 0; + TRACE("returning %s as label\n", debugstr_w(entry->cAlternateFileName)); + return 1; + } + + + if (!INT21_FindHandle || INT21_FindPath != fullPath || count == 0) + { + if (INT21_FindHandle) FindClose(INT21_FindHandle); + INT21_FindHandle = FindFirstFileW(fullPath, entry); + if (INT21_FindHandle == INVALID_HANDLE_VALUE) + { + INT21_FindHandle = 0; + return 0; + } + INT21_FindPath = fullPath; + /* we need to resync search */ + ncalls = count; + } + else ncalls = 1; + + while (ncalls-- != 0) + { + if (!FindNextFileW(INT21_FindHandle, entry)) + { + FindClose(INT21_FindHandle); INT21_FindHandle = 0; + return 0; + } + } + while (count < 0xffff) + { + count++; + /* Check the file attributes, and path */ + if (!(entry->dwFileAttributes & ~search_attr) && + match_short(entry->cAlternateFileName, mask)) + { + return count; + } + if (!FindNextFileW(INT21_FindHandle, entry)) + { + FindClose(INT21_FindHandle); INT21_FindHandle = 0; + return 0; + } + } + WARN("Too many directory entries in %s\n", debugstr_w(fullPath) ); + return 0; +} + +/****************************************************************** + * INT21_FindNext + */ +static int INT21_FindNext( CONTEXT86 *context ) +{ + FINDFILE_DTA *dta = (FINDFILE_DTA *)INT21_GetCurrentDTA(context); + DWORD attr = dta->search_attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY; + WIN32_FIND_DATAW entry; + int n; + + if (!dta->fullPath) return 0; + + n = INT21_FindHelper(dta->fullPath, dta->drive, dta->count, + dta->mask, attr, &entry); + if (n) + { + dta->fileattr = entry.dwFileAttributes; + dta->filesize = entry.nFileSizeLow; + FileTimeToDosDateTime( &entry.ftLastWriteTime, &dta->filedate, &dta->filetime ); + WideCharToMultiByte(CP_OEMCP, 0, entry.cAlternateFileName, -1, + dta->filename, 13, NULL, NULL); + 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->fullPath ); + INT21_FindPath = dta->fullPath = NULL; + } + dta->count += n; + return 1; + } + HeapFree( GetProcessHeap(), 0, dta->fullPath ); + INT21_FindPath = dta->fullPath = NULL; + return 0; +} + +/* microsoft's programmers should be shot for using CP/M style int21 + calls in Windows for Workgroup's winfile.exe */ + +/****************************************************************** + * INT21_FindFirstFCB + * + */ +static int INT21_FindFirstFCB( CONTEXT86 *context ) +{ + BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); + FINDFILE_FCB *pFCB; + int drive; + WCHAR p[] = {' ',':',}; + + if (*fcb == 0xff) pFCB = (FINDFILE_FCB *)(fcb + 7); + else pFCB = (FINDFILE_FCB *)fcb; + drive = INT21_MapDrive( pFCB->drive ); + if (drive == MAX_DOS_DRIVES) return 0; + + p[0] = 'A' + drive; + pFCB->fullPath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + if (!pFCB->fullPath) return 0; + GetLongPathNameW(p, pFCB->fullPath, MAX_PATH); + pFCB->count = 0; + return 1; +} + +/****************************************************************** + * INT21_FindNextFCB + * + */ +static int INT21_FindNextFCB( CONTEXT86 *context ) +{ + 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); + WIN32_FIND_DATAW entry; + BYTE attr; + int n; + WCHAR nameW[12]; + + if (*fcb == 0xff) /* extended FCB ? */ + { + attr = fcb[6]; + pFCB = (FINDFILE_FCB *)(fcb + 7); + } + else + { + attr = 0; + pFCB = (FINDFILE_FCB *)fcb; + } + + if (!pFCB->fullPath) return 0; + n = INT21_FindHelper(pFCB->fullPath, INT21_MapDrive( pFCB->drive ), + pFCB->count, pFCB->filename, attr, &entry); + if (!n) + { + HeapFree( GetProcessHeap(), 0, pFCB->fullPath ); + INT21_FindPath = pFCB->fullPath = NULL; + return 0; + } + pFCB->count += 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)++; + } + *(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) ); + FileTimeToDosDateTime( &entry.ftLastWriteTime, + &pResult->filedate, &pResult->filetime ); + + /* Convert file name to FCB format */ + INT21_ToDosFCBFormat( entry.cAlternateFileName, nameW ); + WideCharToMultiByte(CP_OEMCP, 0, nameW, 11, pResult->filename, 11, NULL, NULL); + return 1; +} + + +/****************************************************************** + * INT21_ParseFileNameIntoFCB + * + */ +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 *s; + WCHAR *buffer; + WCHAR fcbW[12]; + INT buffer_len, len; + + SET_AL( context, 0xff ); /* failed */ + + TRACE("filename: '%s'\n", filename); + + s = filename; + while (*s && (*s != ' ') && (*s != '\r') && (*s != '\n')) + s++; + len = filename - s; + + buffer_len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, NULL, 0); + buffer = HeapAlloc( GetProcessHeap(), 0, (buffer_len + 1) * sizeof(WCHAR)); + len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, buffer, buffer_len); + buffer[len] = 0; + INT21_ToDosFCBFormat(buffer, fcbW); + HeapFree(GetProcessHeap(), 0, buffer); + WideCharToMultiByte(CP_OEMCP, 0, fcbW, 12, fcb + 1, 12, NULL, NULL); + *fcb = 0; + TRACE("FCB: '%s'\n", fcb + 1); + + SET_AL( context, ((strchr(filename, '*')) || (strchr(filename, '$'))) != 0 ); + + /* point DS:SI to first unparsed character */ + SET_SI( context, context->Esi + (int)s - (int)filename ); +} /*********************************************************************** * DOSVM_Int21Handler @@ -3061,11 +3898,20 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) 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)) + { + SET_AL( context, 0xff ); + break; + } + /* else fall through */ + case 0x12: /* FIND NEXT MATCHING FILE USING FCB */ - INT_Int21Handler( context ); + SET_AL( context, INT21_FindNextFCB(context) ? 0x00 : 0xff ); break; - case 0x13: /* DELETE FILE USING FCB */ + case 0x13: /* DELETE FILE USING FCB */ INT_BARF( context, 0x21 ); break; @@ -3101,8 +3947,13 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */ + if (!INT21_GetDriveAllocInfo(context, 0)) + SET_AX( context, 0xffff ); + break; + case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */ - INT_Int21Handler( context ); + if (!INT21_GetDriveAllocInfo(context, DL_reg(context))) + SET_AX( context, 0xffff ); break; case 0x1d: /* NULL FUNCTION FOR CP/M COMPATIBILITY */ @@ -3169,7 +4020,7 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x29: /* PARSE FILENAME INTO FCB */ - INT_Int21Handler( context ); + INT21_ParseFileNameIntoFCB(context); break; case 0x2a: /* GET SYSTEM DATE */ @@ -3356,7 +4207,9 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x36: /* GET FREE DISK SPACE */ - INT_Int21Handler( context ); + TRACE("GET FREE DISK SPACE FOR DRIVE %s\n", + INT21_DriveName( DL_reg(context) )); + if (!INT21_GetFreeDiskSpace(context)) SET_AX( context, 0xffff ); break; case 0x37: /* SWITCHAR */ @@ -3608,6 +4461,7 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */ TRACE( "FORCEDUP - FORCE DUPLICATE FILE HANDLE %d to %d\n", BX_reg(context), CX_reg(context) ); + if (FILE_Dup2( BX_reg(context), CX_reg(context) ) == HFILE_ERROR16) bSetDOSExtendedError = TRUE; else @@ -3754,8 +4608,20 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *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 */ - INT_Int21Handler( context ); + TRACE("FINDNEXT\n"); + if (!INT21_FindNext(context)) + { + SetLastError( ERROR_NO_MORE_FILES ); + SET_AX( context, ERROR_NO_MORE_FILES ); + SET_CFLAG(context); + } + else SET_AX( context, 0 ); /* OK */ break; case 0x50: /* SET CURRENT PROCESS ID (SET PSP ADDRESS) */ @@ -3834,7 +4700,8 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x5a: /* CREATE TEMPORARY FILE */ - INT_Int21Handler( context ); + TRACE("CREATE TEMPORARY FILE\n"); + bSetDOSExtendedError = !INT21_CreateTempFile(context); break; case 0x5b: /* CREATE NEW FILE */ @@ -3881,9 +4748,38 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x5e: /* NETWORK 5E */ + bSetDOSExtendedError = INT21_NetworkFunc( context); + break; + case 0x5f: /* NETWORK 5F */ + /* FIXME: supporting this would need to 1: + * - implement per drive current directory (as kernel32 doesn't) + * - assign enabled/disabled flag on a per drive basis + */ + /* network software not installed */ + TRACE("NETWORK function AX=%04x not implemented\n",AX_reg(context)); + SetLastError( ER_NoNetwork ); + bSetDOSExtendedError = TRUE; + break; + case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */ - INT_Int21Handler( context ); + { + WCHAR pathW[MAX_PATH], res[MAX_PATH]; + /* FIXME: likely to be broken */ + + TRACE("TRUENAME %s\n", + (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Esi)); + MultiByteToWideChar(CP_OEMCP, 0, CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi), -1, pathW, MAX_PATH); + if (!GetFullPathNameW( pathW, 128, res, NULL )) + bSetDOSExtendedError = TRUE; + else + { + SET_AX( context, 0 ); + WideCharToMultiByte(CP_OEMCP, 0, res, -1, + CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi), + 128, NULL, NULL); + } + } break; case 0x61: /* UNUSED */ @@ -3942,7 +4838,22 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context ) break; case 0x69: /* DISK SERIAL NUMBER */ - INT_Int21Handler( context ); + switch (AL_reg(context)) + { + case 0x00: + TRACE("GET DISK SERIAL NUMBER for drive %s\n", + INT21_DriveName(BL_reg(context))); + if (!INT21_GetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE; + else SET_AX( context, 0 ); + break; + + case 0x01: + TRACE("SET DISK SERIAL NUMBER for drive %s\n", + INT21_DriveName(BL_reg(context))); + if (!INT21_SetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE; + else SET_AX( context, 1 ); + break; + } break; case 0x6a: /* COMMIT FILE */ diff --git a/files/dos_fs.c b/files/dos_fs.c index 3712c00b661..7c3a1f847b8 100644 --- a/files/dos_fs.c +++ b/files/dos_fs.c @@ -53,7 +53,6 @@ #include "wine/winbase16.h" #include "drive.h" #include "file.h" -#include "heap.h" #include "msdos.h" #include "winternl.h" #include "wine/server.h" @@ -143,8 +142,6 @@ typedef struct { char *path; /* unix path */ LPWSTR long_mask; - LPWSTR short_mask; - BYTE attr; int drive; int cur_pos; CRITICAL_SECTION cs; @@ -332,20 +329,6 @@ static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer ) } -/*********************************************************************** - * DOSFS_MatchShort - * - * Check a DOS file name against a mask (both in FCB format). - */ -static int DOSFS_MatchShort( LPCWSTR mask, LPCWSTR name ) -{ - int i; - for (i = 11; i > 0; i--, mask++, name++) - if ((*mask != '?') && (*mask != *name)) return 0; - return 1; -} - - /*********************************************************************** * DOSFS_MatchLong * @@ -1777,35 +1760,14 @@ static BOOL get_show_dir_symlinks_option(void) */ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry ) { - DWORD attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY; UINT flags = DRIVE_GetFlags( info->drive ); char *p, buffer[MAX_PATHNAME_LEN]; const char *drive_path; int drive_root; LPCWSTR long_name, short_name; BY_HANDLE_FILE_INFORMATION fileinfo; - WCHAR dos_name[13]; BOOL is_symlink; - if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL) - { - if (info->cur_pos) return 0; - entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL; - 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->nFileSizeHigh = 0; - entry->nFileSizeLow = 0; - entry->dwReserved0 = 0; - entry->dwReserved1 = 0; - DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName ); - strcpyW( entry->cAlternateFileName, entry->cFileName ); - info->cur_pos++; - TRACE("returning %s (%s) as label\n", - debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName)); - return 1; - } - drive_path = info->path + strlen(DRIVE_GetRoot( info->drive )); while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++; drive_root = !*drive_path; @@ -1831,19 +1793,6 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry ) flags & DRIVE_CASE_SENSITIVE )) continue; } - /* Check the short mask */ - - if (info->short_mask) - { - if (!short_name) - { - DOSFS_Hash( long_name, dos_name, TRUE, - !(flags & DRIVE_CASE_SENSITIVE) ); - short_name = dos_name; - } - if (!DOSFS_MatchShort( info->short_mask, short_name )) continue; - } - /* Check the file attributes */ WideCharToMultiByte(CP_UNIXCP, 0, long_name, -1, p, sizeof(buffer) - (int)(p - buffer), NULL, NULL); @@ -1860,8 +1809,6 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry ) if (!show_dir_symlinks) continue; } - if (fileinfo.dwFileAttributes & ~attr) continue; - /* We now have a matching entry; fill the result and return */ entry->dwFileAttributes = fileinfo.dwFileAttributes; @@ -1887,94 +1834,6 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry ) return 0; /* End of directory */ } -/*********************************************************************** - * DOSFS_FindNext - * - * Find the next matching file. Return the number of entries read to find - * the matching one, or 0 if no more entries. - * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long - * file name mask. Either or both can be NULL. - * - * NOTE: This is supposed to be only called by the int21 emulation - * routines, and so assumes that the Win16Mutex is held to - * protect the static directory cache. - */ -int DOSFS_FindNext( const char *path, const char *short_mask, - const char *long_mask, int drive, BYTE attr, - int skip, WIN32_FIND_DATAA *entry ) -{ - static FIND_FIRST_INFO info; - LPCWSTR short_name, long_name; - int count; - UNICODE_STRING short_maskW, long_maskW; - WIN32_FIND_DATAW entryW; - - TRACE("(%s, %s, %s, %x, %x, %x, %p)\n", debugstr_a(path), - debugstr_a(short_mask), debugstr_a(long_mask), drive, attr, skip, - entry); - - RtlCreateUnicodeStringFromAsciiz(&short_maskW, short_mask); - RtlCreateUnicodeStringFromAsciiz(&long_maskW, long_mask); - - /* Check the cached directory */ - if (!(info.u.dos_dir && info.path == path && !strcmpW(info.short_mask, short_maskW.Buffer) - && !strcmpW(info.long_mask, long_maskW.Buffer) && info.drive == drive - && info.attr == attr && info.cur_pos <= skip)) - { - /* Not in the cache, open it anew */ - if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir ); - - info.path = (LPSTR)path; - RtlFreeHeap(GetProcessHeap(), 0, info.long_mask); - RtlFreeHeap(GetProcessHeap(), 0, info.short_mask); - info.long_mask = long_maskW.Buffer; - info.short_mask = short_maskW.Buffer; - info.attr = attr; - info.drive = drive; - info.cur_pos = 0; - info.u.dos_dir = DOSFS_OpenDir( info.path ); - } - else - { - RtlFreeUnicodeString(&short_maskW); - RtlFreeUnicodeString(&long_maskW); - } - - /* Skip to desired position */ - while (info.cur_pos < skip) - if (info.u.dos_dir && DOSFS_ReadDir( info.u.dos_dir, &long_name, &short_name )) - info.cur_pos++; - else - break; - - if (info.u.dos_dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, &entryW )) - { - WideCharToMultiByte(CP_ACP, 0, entryW.cFileName, -1, - entry->cFileName, sizeof(entry->cFileName), NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, entryW.cAlternateFileName, -1, - entry->cAlternateFileName, sizeof(entry->cAlternateFileName), NULL, NULL); - count = info.cur_pos - skip; - - entry->dwFileAttributes = entryW.dwFileAttributes; - entry->nFileSizeHigh = entryW.nFileSizeHigh; - entry->nFileSizeLow = entryW.nFileSizeLow; - entry->ftCreationTime = entryW.ftCreationTime; - entry->ftLastAccessTime = entryW.ftLastAccessTime; - entry->ftLastWriteTime = entryW.ftLastWriteTime; - - } - else - count = 0; - - if (!count) - { - if (info.u.dos_dir) DOSFS_CloseDir( info.u.dos_dir ); - memset( &info, '\0', sizeof(info) ); - } - - return count; -} - /************************************************************************* * FindFirstFileExW (KERNEL32.@) */ @@ -2048,8 +1907,6 @@ HANDLE WINAPI FindFirstFileExW( info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) ); MultiByteToWideChar(CP_UNIXCP, 0, p, -1, info->long_mask, long_mask_len); - info->short_mask = NULL; - info->attr = 0xff; info->drive = full_name.drive; info->cur_pos = 0; @@ -2469,13 +2326,3 @@ DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize) } return ret; } - - -/*********************************************************************** - * DefineDosDeviceA (KERNEL32.@) - */ -BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) { - FIXME("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} diff --git a/files/drive.c b/files/drive.c index 8cf95ac053f..cf18e665bc9 100644 --- a/files/drive.c +++ b/files/drive.c @@ -1283,21 +1283,54 @@ int DRIVE_Enable( int drive ) /*********************************************************************** - * DRIVE_SetLogicalMapping + * DefineDosDeviceA (KERNEL32.@) */ -int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive ) +BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) { - /* If new_drive is already valid, do nothing and return 0 - otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */ + UNICODE_STRING d, t; + BOOL ret; + if (!RtlCreateUnicodeStringFromAsciiz(&d, devname)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + if (!RtlCreateUnicodeStringFromAsciiz(&t, targetpath)) + { + RtlFreeUnicodeString(&d); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + ret = DefineDosDeviceW(flags, d.Buffer, t.Buffer); + RtlFreeUnicodeString(&d); + RtlFreeUnicodeString(&t); + return ret; +} + + +/*********************************************************************** + * DefineDosDeviceA (KERNEL32.@) + */ +BOOL WINAPI DefineDosDeviceW(DWORD flags,LPCWSTR devname,LPCWSTR targetpath) +{ DOSDRIVE *old, *new; - old = DOSDrives + existing_drive; - new = DOSDrives + new_drive; + /* this is a temporary hack for int21 support. better implementation has to be done */ + if (flags != DDD_RAW_TARGET_PATH || + !(toupperW(devname[0]) >= 'A' && toupperW(devname[0]) <= 'Z') || + devname[1] != ':' || devname[2] != 0 || + !(toupperW(targetpath[0]) >= 'A' && toupperW(targetpath[0]) <= 'Z') || + targetpath[1] != ':' || targetpath[2] != '\\' || targetpath[3] != 0) + { + FIXME("(0x%08lx,%s,%s),stub!\n", flags, debugstr_w(devname), debugstr_w(targetpath)); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } - if ((existing_drive < 0) || (existing_drive >= MAX_DOS_DRIVES) || - !old->root || - (new_drive < 0) || (new_drive >= MAX_DOS_DRIVES)) + old = DOSDrives + devname[0] - 'A'; + new = DOSDrives + targetpath[0] - 'A'; + + if (!old->root) { SetLastError( ERROR_INVALID_DRIVE ); return 0; @@ -1306,7 +1339,7 @@ int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive ) if ( new->root ) { TRACE("Can't map drive %c: to already existing drive %c:\n", - 'A' + existing_drive, 'A' + new_drive ); + devname[0], targetpath[0] ); /* it is already mapped there, so return success */ if (!strcmp(old->root,new->root)) return 1; @@ -1327,7 +1360,7 @@ int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive ) new->ino = old->ino; TRACE("Drive %c: is now equal to drive %c:\n", - 'A' + new_drive, 'A' + existing_drive ); + targetpath[0], devname[0] ); return 1; } @@ -2126,8 +2159,8 @@ BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname) /*********************************************************************** * GetVolumeNameForVolumeMountPointW (KERNEL32.@) */ -DWORD WINAPI GetVolumeNameForVolumeMountPointW(LPWSTR str, DWORD a, DWORD b) +BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size) { - FIXME("(%s, %lx, %lx): stub\n", debugstr_w(str), a, b); + FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size); return 0; } diff --git a/include/drive.h b/include/drive.h index 079a879a35a..8e7436859ad 100644 --- a/include/drive.h +++ b/include/drive.h @@ -51,7 +51,6 @@ extern UINT DRIVE_GetFlags( int drive ); extern int DRIVE_Chdir( int drive, LPCWSTR path ); extern int DRIVE_Disable( int drive ); extern int DRIVE_Enable( int drive ); -extern int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive ); extern int DRIVE_OpenDevice( int drive, int flags ); extern WCHAR *DRIVE_BuildEnv(void); diff --git a/include/file.h b/include/file.h index 64657a1dbf6..65e5721c170 100644 --- a/include/file.h +++ b/include/file.h @@ -97,9 +97,6 @@ extern BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *l INT long_len, LPWSTR short_buf, BOOL ignore_case ); extern BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last, DOS_FULL_NAME *full ); -extern int DOSFS_FindNext( const char *path, const char *short_mask, - const char *long_mask, int drive, BYTE attr, - int skip, WIN32_FIND_DATAA *entry ); /* win32/device.c */ extern HANDLE DEVICE_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ); diff --git a/include/msdos.h b/include/msdos.h index d2fe189b38f..74f77d9f6fd 100644 --- a/include/msdos.h +++ b/include/msdos.h @@ -44,7 +44,7 @@ typedef struct BYTE search_attr; /* 0c search attributes */ WORD count; /* 0d entry count within directory */ WORD cluster; /* 0f cluster of parent directory */ - char *unixPath; /* 11 unix path (was: reserved) */ + WCHAR *fullPath; /* 11 full path (was: reserved) */ BYTE fileattr; /* 15 file attributes */ WORD filetime; /* 16 file time */ WORD filedate; /* 18 file date */ @@ -58,7 +58,7 @@ typedef struct BYTE drive; /* 00 drive letter */ char filename[11]; /* 01 filename 8+3 format */ int count; /* 0c entry count (was: reserved) */ - char *unixPath; /* 10 unix path (was: reserved) */ + WCHAR *fullPath; /* 10 full path (was: reserved) */ } FINDFILE_FCB; /* DOS directory entry for FindFirstFCB/FindNextFCB */ diff --git a/include/winbase.h b/include/winbase.h index b97317fa713..47315ca15a6 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1090,6 +1090,13 @@ BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ); BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ); #define GetBinaryType WINELIB_NAME_AW(GetBinaryType) +/* flags for DefineDosDevice */ +#define DDD_RAW_TARGET_PATH 0x00000001 +#define DDD_REMOVE_DEFINITION 0x00000002 +#define DDD_EXACT_MATCH_ON_REMOVE 0x00000004 +#define DDD_NO_BROADCAST_SYSTEM 0x00000008 +#define DDD_LUID_BROADCAST_DRIVE 0x00000010 + BOOL WINAPI AddAccessAllowedAce(PACL,DWORD,DWORD,PSID); PVOID WINAPI AddVectoredExceptionHandler(ULONG,PVECTORED_EXCEPTION_HANDLER); BOOL WINAPI AttachThreadInput(DWORD,DWORD,BOOL); @@ -1182,10 +1189,16 @@ BOOL WINAPI DebugActiveProcessStop(DWORD); void WINAPI DebugBreak(void); BOOL WINAPI DebugBreakProcess(HANDLE); BOOL WINAPI DebugSetProcessKillOnExit(BOOL); +BOOL WINAPI DefineDosDeviceA(DWORD,LPCSTR,LPCSTR); +BOOL WINAPI DefineDosDeviceW(DWORD,LPCWSTR,LPCWSTR); +#define DefineDosDevice WINELIB_NAME_AW(DefineDosDevice) BOOL WINAPI DeleteAce(PACL,DWORD); void WINAPI DeleteFiber(LPVOID); BOOL WINAPI DeleteTimerQueueEx(HANDLE,HANDLE); BOOL WINAPI DeleteTimerQueueTimer(HANDLE,HANDLE,HANDLE); +BOOL WINAPI DeleteVolumeMountPointA(LPCSTR); +BOOL WINAPI DeleteVolumeMountPointW(LPCWSTR); +#define DeleteVolumeMountPoint WINELIB_NAME_AW(DeleteVolumeMountPoint) BOOL WINAPI DeregisterEventSource(HANDLE); BOOL WINAPI DeviceIoControl(HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPOVERLAPPED); BOOL WINAPI DisableThreadLibraryCalls(HMODULE); @@ -1224,6 +1237,20 @@ BOOL WINAPI FindCloseChangeNotification(HANDLE); HRSRC WINAPI FindResourceExA(HMODULE,LPCSTR,LPCSTR,WORD); HRSRC WINAPI FindResourceExW(HMODULE,LPCWSTR,LPCWSTR,WORD); #define FindResourceEx WINELIB_NAME_AW(FindResourceEx) +HANDLE WINAPI FindFirstVolumeA(LPSTR,DWORD); +HANDLE WINAPI FindFirstVolumeW(LPWSTR,DWORD); +#define FindFirstVolume WINELIB_NAME_AW(FindFirstVolume) +HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR,LPSTR,DWORD); +HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR,LPWSTR,DWORD); +#define FindFirstVolumeMountPoint WINELIB_NAME_AW(FindFirstVolumeMountPoint) +BOOL WINAPI FindNextVolumeA(HANDLE,LPSTR,DWORD); +BOOL WINAPI FindNextVolumeW(HANDLE,LPWSTR,DWORD); +#define FindNextVolume WINELIB_NAME_AW(FindNextVolume) +BOOL WINAPI FindNextVolumeMountPointA(HANDLE,LPSTR,DWORD); +BOOL WINAPI FindNextVolumeMountPointW(HANDLE,LPWSTR,DWORD); +#define FindNextVolumeMountPoint WINELIB_NAME_AW(FindNextVolumeMountPoint) +BOOL WINAPI FindVolumeClose(HANDLE); +BOOL WINAPI FindVolumeMountPointClose(HANDLE); BOOL WINAPI FlushFileBuffers(HANDLE); BOOL WINAPI FlushViewOfFile(LPCVOID,SIZE_T); DWORD WINAPI FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list*); @@ -1323,6 +1350,15 @@ BOOL WINAPI GetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,LPVOID,DWO BOOL WINAPI GetUserNameA(LPSTR,LPDWORD); BOOL WINAPI GetUserNameW(LPWSTR,LPDWORD); #define GetUserName WINELIB_NAME_AW(GetUserName) +BOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR,LPSTR,DWORD); +BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR,LPWSTR,DWORD); +#define GetVolumeNameForVolumeMountPoint WINELIB_NAME_AW(GetVolumeNameForVolumeMountPoint) +BOOL WINAPI GetVolumePathNameA(LPCSTR,LPSTR,DWORD); +BOOL WINAPI GetVolumePathNameW(LPCWSTR,LPWSTR,DWORD); +#define GetVolumePathName WINELIB_NAME_AW(GetVolumePathName) +BOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR,LPSTR,DWORD,PDWORD); +BOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR,LPWSTR,DWORD,PDWORD); +#define GetVolumePathNamesForVolumeName WINELIB_NAME_AW(GetVolumePathNamesForVolumeName) VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS); LPVOID WINAPI HeapAlloc(HANDLE,DWORD,SIZE_T); SIZE_T WINAPI HeapCompact(HANDLE,DWORD); @@ -1473,6 +1509,9 @@ BOOL WINAPI SetThreadPriority(HANDLE,INT); BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL); BOOL WINAPI SetThreadToken(PHANDLE,HANDLE); BOOL WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION); +BOOL WINAPI SetVolumeMountPointA(LPCSTR,LPCSTR); +BOOL WINAPI SetVolumeMountPointW(LPCSTR,LPCSTR); +#define SetVolumeMountPoint WINELIB_NAME_AW(SetVolumeMountPoint) BOOL WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,LPVOID,BOOL); BOOL WINAPI SetupComm(HANDLE,DWORD,DWORD); DWORD WINAPI SignalObjectAndWait(HANDLE,HANDLE,DWORD,BOOL); diff --git a/msdos/int21.c b/msdos/int21.c deleted file mode 100644 index 0ab3a926587..00000000000 --- a/msdos/int21.c +++ /dev/null @@ -1,837 +0,0 @@ -/* - * 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 "wine/port.h" - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_FILE_H -# include -#endif -#include -#ifdef HAVE_SYS_TIME_H -# include -#endif -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_UTIME_H -# include -#endif -#include -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "wingdi.h" -#include "winuser.h" /* SW_NORMAL */ -#include "wine/winbase16.h" -#include "winerror.h" -#include "drive.h" -#include "file.h" -#include "msdos.h" -#include "miscemu.h" -#include "task.h" -#include "kernel_private.h" -#include "wine/unicode.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 -#define LOCK_SH 1 -#define LOCK_NB 8 -#endif - - -#define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive()) - -struct DosHeap { - BYTE mediaID; - BYTE biosdate[8]; -}; -static struct DosHeap *heap; -static WORD DosHeapHandle; - -extern char TempDirectory[]; - -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); - strcpy(heap->biosdate, "01/01/80"); - return TRUE; -} - -static BYTE *GetCurrentDTA( CONTEXT86 *context ) -{ - TDB *pTask = GlobalLock16(GetCurrentTask()); - - /* FIXME: This assumes DTA was set correctly! */ - return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta), - (DWORD)OFFSETOF(pTask->dta) ); -} - - -static 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; - SET_AX( context, cluster_sectors ); - SET_BX( context, free_clusters ); - SET_CX( context, sector_bytes ); - SET_DX( context, total_clusters ); - return 1; -} - -static int INT21_GetDriveAllocInfo( CONTEXT86 *context ) -{ - if (!INT21_GetFreeDiskSpace( context )) return 0; - if (!heap && !INT21_CreateHeap()) return 0; - heap->mediaID = 0xf0; - context->SegDs = DosHeapHandle; - SET_BX( context, (int)&heap->mediaID - (int)heap ); - return 1; -} - -static BOOL ioctlGenericBlkDevReq( CONTEXT86 *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)) - { - SetLastError( ERROR_FILE_NOT_FOUND ); - return TRUE; - } - - if (CH_reg(context) != 0x08) - { - INT_BARF( context, 0x21 ); - return FALSE; - } - - switch (CL_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 */ - } - CreateBPB(drive, &dataptr[7], TRUE); - RESET_CFLAG(context); - break; - - case 0x66:/* get disk serial number */ - { - char label[12],fsname[9],path[4]; - 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); - } - 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 */ - SET_AX( 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 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 *s; - WCHAR *buffer; - WCHAR fcbW[12]; - INT buffer_len, len; - - SET_AL( context, 0xff ); /* failed */ - - TRACE("filename: '%s'\n", filename); - - s = filename; - len = 0; - while (*s) - { - if ((*s != ' ') && (*s != '\r') && (*s != '\n')) - { - s++; - len++; - } - else - break; - } - - buffer_len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, NULL, 0); - buffer = HeapAlloc( GetProcessHeap(), 0, (buffer_len + 1) * sizeof(WCHAR)); - len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, buffer, buffer_len); - buffer[len] = 0; - DOSFS_ToDosFCBFormat(buffer, fcbW); - HeapFree(GetProcessHeap(), 0, buffer); - WideCharToMultiByte(CP_OEMCP, 0, fcbW, 12, fcb + 1, 12, NULL, NULL); - *fcb = 0; - TRACE("FCB: '%s'\n", fcb + 1); - - SET_AL( context, ((strchr(filename, '*')) || (strchr(filename, '$'))) != 0 ); - - /* point DS:SI to first unparsed character */ - SET_SI( context, context->Esi + (int)s - (int)filename ); -} - - -/* Many calls translate a drive argument like this: - drive number (00h = default, 01h = A:, etc) - */ -static const char *INT21_DriveName(int drive) -{ - if (drive > 0) return wine_dbg_sprintf( "%c:", 'A' + drive - 1 ); - return "default"; -} - -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 int INT21_FindFirst( CONTEXT86 *context ) -{ - char *p; - const char *path; - DOS_FULL_NAME full_name; - FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context); - WCHAR pathW[MAX_PATH]; - WCHAR maskW[12]; - - path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); - MultiByteToWideChar(CP_OEMCP, 0, path, -1, pathW, MAX_PATH); - - dta->unixPath = NULL; - if (!DOSFS_GetFullName( pathW, FALSE, &full_name )) - { - SET_AX( context, GetLastError() ); - SET_CFLAG(context); - return 0; - } - dta->unixPath = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); - strcpy( dta->unixPath, full_name.long_name ); - p = strrchr( dta->unixPath, '/' ); - *p = '\0'; - - MultiByteToWideChar(CP_OEMCP, 0, p + 1, -1, pathW, MAX_PATH); - - /* Note: terminating NULL in dta->mask overwrites dta->search_attr - * (doesn't matter as it is set below anyway) - */ - if (!DOSFS_ToDosFCBFormat( pathW, maskW )) - { - HeapFree( GetProcessHeap(), 0, dta->unixPath ); - dta->unixPath = NULL; - SetLastError( ERROR_FILE_NOT_FOUND ); - SET_AX( context, ERROR_FILE_NOT_FOUND ); - SET_CFLAG(context); - return 0; - } - WideCharToMultiByte(CP_OEMCP, 0, maskW, 12, dta->mask, sizeof(dta->mask), NULL, NULL); - 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; - int count; - - if (!dta->unixPath) return 0; - if (!(count = DOSFS_FindNext( dta->unixPath, dta->mask, NULL, dta->drive, - dta->search_attr, dta->count, &entry ))) - { - HeapFree( GetProcessHeap(), 0, dta->unixPath ); - dta->unixPath = NULL; - return 0; - } - if ((int)dta->count + count > 0xffff) - { - WARN("Too many directory entries in %s\n", dta->unixPath ); - HeapFree( GetProcessHeap(), 0, 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; - } - return 1; -} - - -static BOOL INT21_CreateTempFile( CONTEXT86 *context ) -{ - static int counter = 0; - 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; - - SET_AX( context, _lcreat16_uniq( name, 0 ) ); - if (AX_reg(context) != HFILE_ERROR16) - { - TRACE("created %s\n", name ); - return TRUE; - } - if (GetLastError() != ERROR_FILE_EXISTS) return FALSE; - } -} - - -static int INT21_GetDiskSerialNumber( CONTEXT86 *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)) - { - 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); - int drive = DOS_GET_DRIVE( BL_reg(context) ); - - if (!DRIVE_IsValid(drive)) - { - SetLastError( ERROR_INVALID_DRIVE ); - return 0; - } - - 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); - FINDFILE_FCB *pFCB; - LPCSTR root, cwd; - int drive; - - 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( CONTEXT86 *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(context); - WIN32_FIND_DATAA entry; - BYTE attr; - int count; - - if (*fcb == 0xff) /* extended FCB ? */ - { - attr = fcb[6]; - pFCB = (FINDFILE_FCB *)(fcb + 7); - } - else - { - attr = 0; - pFCB = (FINDFILE_FCB *)fcb; - } - - if (!pFCB->unixPath) return 0; - if (!(count = DOSFS_FindNext( pFCB->unixPath, pFCB->filename, NULL, - DOS_GET_DRIVE( pFCB->drive ), attr, - pFCB->count, &entry ))) - { - 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; - 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 ) ); - } - return 1; -} - - -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); - 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; - SET_CH( context, 1 ); /* Valid */ - SET_CL( context, 1 ); /* NETbios number??? */ - TRACE("returning %s\n", debugstr_an (dst, 16)); - return FALSE; - } - } - - default: - SetLastError( ER_NoNetwork ); - return TRUE; - } -} - - -/*********************************************************************** - * INT_Int21Handler - */ -void WINAPI INT_Int21Handler( CONTEXT86 *context ) -{ - BOOL bSetDOSExtendedError = FALSE; - - switch(AH_reg(context)) - { - 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)) - { - SET_AL( context, 0xff ); - break; - } - /* else fall through */ - - case 0x12: /* FIND NEXT MATCHING FILE USING FCB */ - SET_AL( context, INT21_FindNextFCB(context) ? 0x00 : 0xff ); - break; - - case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */ - SET_DL( context, 0 ); - if (!INT21_GetDriveAllocInfo(context)) SET_AX( context, 0xffff ); - break; - - case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */ - if (!INT21_GetDriveAllocInfo(context)) SET_AX( context, 0xffff ); - break; - - case 0x29: /* PARSE FILENAME INTO FCB */ - INT21_ParseFileNameIntoFCB(context); - 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)) SET_AX( context, 0xffff ); - break; - - case 0x44: /* IOCTL */ - switch (AL_reg(context)) - { - case 0x0d: - TRACE("IOCTL - GENERIC BLOCK DEVICE REQUEST %s\n", - INT21_DriveName( BL_reg(context))); - bSetDOSExtendedError = ioctlGenericBlkDevReq(context); - break; - - case 0x0F: /* Set logical drive mapping */ - { - 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); - SET_AX( context, 0x000F ); /* invalid drive */ - } - break; - } - } - 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)) - { - SetLastError( ERROR_NO_MORE_FILES ); - SET_AX( context, ERROR_NO_MORE_FILES ); - SET_CFLAG(context); - } - else SET_AX( context, 0 ); /* OK */ - break; - - case 0x5a: /* CREATE TEMPORARY FILE */ - TRACE("CREATE TEMPORARY FILE\n"); - bSetDOSExtendedError = !INT21_CreateTempFile(context); - break; - - case 0x5e: - 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) )) - { - 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) )) - { - SetLastError( ERROR_INVALID_DRIVE ); - bSetDOSExtendedError = TRUE; - } - break; - - default: - /* network software not installed */ - 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)); - { - 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 SET_AX( context, 0 ); - } - break; - - case 0x69: /* DISK SERIAL NUMBER */ - switch (AL_reg(context)) - { - case 0x00: - TRACE("GET DISK SERIAL NUMBER for drive %s\n", - INT21_DriveName(BL_reg(context))); - if (!INT21_GetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE; - else SET_AX( context, 0 ); - break; - - case 0x01: - TRACE("SET DISK SERIAL NUMBER for drive %s\n", - INT21_DriveName(BL_reg(context))); - if (!INT21_SetDiskSerialNumber(context)) bSetDOSExtendedError = TRUE; - else SET_AX( context, 1 ); - break; - } - break; - - case 0x71: /* MS-DOS 7 (Windows95) - LONG FILENAME FUNCTIONS */ - switch(AL_reg(context)) - { - 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 */ - SET_AX( 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))); - if (AX_reg(context) == 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_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); - SET_AX( context, 0 ); - if (!GetVolumeInformationA( driveroot, NULL, 0, NULL, &filename_len, - &flags, buffer, 8 )) - { - INT_BARF( context, 0x21 ); - SET_CFLAG(context); - break; - } - SET_BX( context, flags | 0x4000 ); /* support for LFN functions */ - SET_CX( context, filename_len ); - SET_DX( context, MAX_PATH ); /* FIXME: which len if DRIVE_SHORT_NAMES ? */ - } - break; - case 0xa1: /* Find close */ - TRACE("LONG FILENAME - FINDCLOSE for handle %d\n", - BX_reg(context)); - bSetDOSExtendedError = (!FindClose16( BX_reg(context) )); - break; - 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 SET_AX( 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 SET_AX( context, 0 ); - break; - default: - FIXME("Unimplemented long file name function:\n"); - INT_BARF( context, 0x21 ); - SET_CFLAG(context); - SET_AL( context, 0 ); - break; - } - break; - - default: - FIXME("Unimplemented long file name function:\n"); - INT_BARF( context, 0x21 ); - SET_CFLAG(context); - SET_AL( context, 0 ); - break; - } - break; - - default: - INT_BARF( context, 0x21 ); - break; - - } /* END OF SWITCH */ - - if( bSetDOSExtendedError ) /* set general error condition */ - { - SET_AX( context, GetLastError() ); - SET_CFLAG(context); - } -}