- 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/winebase.h - started DefineDosDevice (needed by first item in this list) - removed int21 specific code from dlls/kernel32
A+ -- Eric Pouech
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel35/kernel32.spec dlls/kernel/kernel32.spec --- dlls/kernel35/kernel32.spec 2003-11-09 19:31:14.000000000 +0100 +++ dlls/kernel/kernel32.spec 2003-11-11 22:34:11.000000000 +0100 @@ -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 -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel35/Makefile.in dlls/kernel/Makefile.in --- dlls/kernel35/Makefile.in 2003-11-12 21:46:50.000000000 +0100 +++ dlls/kernel/Makefile.in 2003-11-12 20:44:18.000000000 +0100 @@ -29,7 +29,6 @@ $(TOPOBJDIR)/misc/options.c \ $(TOPOBJDIR)/misc/registry.c \ $(TOPOBJDIR)/msdos/dpmi.c \ - $(TOPOBJDIR)/msdos/int21.c \ atom.c \ change.c \ comm.c \ diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/winedos35/int21.c dlls/winedos/int21.c --- dlls/winedos35/int21.c 2003-11-11 13:58:09.000000000 +0100 +++ dlls/winedos/int21.c 2003-11-13 21:15:49.000000000 +0100 @@ -26,6 +26,10 @@ #include "config.h" #include <stdarg.h> +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#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 @@ #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( "<Bad drive: %d>", 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 +2654,20 @@ return TRUE; } +static void INT21_ConvertFindDataAtoW(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 +2677,8 @@ static void INT21_LongFilename( CONTEXT86 *context ) { BOOL bSetDOSExtendedError = FALSE; + WCHAR pathW[MAX_PATH]; + char* pathA; if (HIBYTE(HIWORD(GetVersion16())) < 0x07) { @@ -2560,17 +2700,11 @@ 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 +2713,12 @@ 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 +2732,63 @@ 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_ConvertFindDataAtoW(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_ConvertFindDataAtoW(dataA, &dataW); + GlobalUnlock16( h16 ); + } + else + { + SetLastError( ERROR_INVALID_HANDLE ); + bSetDOSExtendedError = TRUE; + } + } break; case 0x56: /* LONG FILENAME - RENAME FILE */ @@ -2613,7 +2797,44 @@ 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 +2844,52 @@ 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 +2955,11 @@ 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) @@ -2729,6 +2996,134 @@ /*********************************************************************** + * 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 */ static void INT21_GetExtendedError( CONTEXT86 *context ) @@ -2843,6 +3238,452 @@ 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 void* 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(((WCHAR*)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 +3902,20 @@ 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 +3951,13 @@ 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 +4024,7 @@ break; case 0x29: /* PARSE FILENAME INTO FCB */ - INT_Int21Handler( context ); + INT21_ParseFileNameIntoFCB(context); break; case 0x2a: /* GET SYSTEM DATE */ @@ -3356,7 +4211,9 @@ 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 +4465,7 @@ 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 +4612,20 @@ 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 +4704,8 @@ 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 +4752,38 @@ 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 +4842,22 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS files35/dos_fs.c files/dos_fs.c --- files35/dos_fs.c 2003-11-09 19:31:34.000000000 +0100 +++ files/dos_fs.c 2003-11-11 22:26:10.000000000 +0100 @@ -143,8 +143,6 @@ { char *path; /* unix path */ LPWSTR long_mask; - LPWSTR short_mask; - BYTE attr; int drive; int cur_pos; CRITICAL_SECTION cs; @@ -333,20 +331,6 @@ /*********************************************************************** - * 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 * * Check a long file name against a mask. @@ -1777,35 +1761,14 @@ */ 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 +1794,6 @@ 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 +1810,6 @@ 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 +1835,6 @@ 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 +1908,6 @@ 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; @@ -2470,12 +2328,3 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS files35/drive.c files/drive.c --- files35/drive.c 2003-11-09 19:31:34.000000000 +0100 +++ files/drive.c 2003-11-11 22:26:52.000000000 +0100 @@ -1283,21 +1283,54 @@ /*********************************************************************** - * 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; + } + + old = DOSDrives + devname[0] - 'A'; + new = DOSDrives + targetpath[0] - 'A'; - if ((existing_drive < 0) || (existing_drive >= MAX_DOS_DRIVES) || - !old->root || - (new_drive < 0) || (new_drive >= MAX_DOS_DRIVES)) + if (!old->root) { SetLastError( ERROR_INVALID_DRIVE ); return 0; @@ -1306,7 +1339,7 @@ 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 @@ 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 @@ /*********************************************************************** * 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 -u -N -r -x '*~' -x '.#*' -x CVS include35/drive.h include/drive.h --- include35/drive.h 2003-11-09 19:31:36.000000000 +0100 +++ include/drive.h 2003-11-13 21:18:10.000000000 +0100 @@ -51,7 +51,6 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS include35/file.h include/file.h --- include35/file.h 2003-11-09 19:31:36.000000000 +0100 +++ include/file.h 2003-11-11 22:18:51.000000000 +0100 @@ -97,9 +97,6 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS include35/msdos.h include/msdos.h --- include35/msdos.h 2003-09-13 21:06:50.000000000 +0200 +++ include/msdos.h 2003-11-11 11:32:25.000000000 +0100 @@ -44,7 +44,7 @@ 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) */ + void *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 @@ 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) */ + void *fullPath; /* 10 full path (was: reserved) */ } FINDFILE_FCB; /* DOS directory entry for FindFirstFCB/FindNextFCB */ diff -u -N -r -x '*~' -x '.#*' -x CVS include35/winbase.h include/winbase.h --- include35/winbase.h 2003-11-12 21:47:43.000000000 +0100 +++ include/winbase.h 2003-11-12 20:55:57.000000000 +0100 @@ -1090,6 +1090,13 @@ 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 @@ 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 @@ 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 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 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);