ntdll / kernel32: #36

Eric Pouech pouech-eric at wanadoo.fr
Thu Nov 13 14:26:12 CST 2003


- 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
-------------- next part --------------
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, &sector_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);


More information about the wine-patches mailing list