final int21 move (2/11)

György 'Nog' Jeney nog at sdf.lonestar.org
Wed Nov 27 14:12:57 CST 2002


> On November 27, 2002 12:37 pm, György 'Nog' Jeney wrote:
>> ChangeLog:
>>  * dlls/winedos/int21.c
>>  * msdos/int21.c
>>  * include/msdos.h
>>  * files/dos_fs.h
>>  * include/file.h
>>    Move Find{First|Next}{FCB|} fucntions to winedos.
>
> Dude, where's the patch? :)

Right here :)

nog.

-------------- next part --------------
--- msdos/int21.c.1	2002-11-27 15:36:00.000000000 +0200
+++ msdos/int21.c	2002-11-27 15:36:23.000000000 +0200
@@ -159,16 +159,6 @@
     return TRUE;
 }
 
-static BYTE *GetCurrentDTA( CONTEXT86 *context )
-{
-    TDB *pTask = TASK_GetCurrent();
-
-    /* FIXME: This assumes DTA was set correctly! */
-    return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta),
-                                                (DWORD)OFFSETOF(pTask->dta) );
-}
-
-
 void CreateBPB(int drive, BYTE *data, BOOL16 limited)
 /* limited == TRUE is used with INT 0x21/0x440d */
 {
@@ -424,50 +414,6 @@
 	return FALSE;
 }
 
-static void INT21_ParseFileNameIntoFCB( CONTEXT86 *context )
-{
-    char *filename =
-        CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi );
-    char *fcb =
-        CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi );
-    char *s;
-    WCHAR *buffer;
-    WCHAR fcbW[12];
-    INT buffer_len, len;
-
-    SET_AL( context, 0xff ); /* failed */
-
-    TRACE("filename: '%s'\n", filename);
-
-    s = filename;
-    len = 0;
-    while (*s)
-    {
-        if ((*s != ' ') && (*s != '\r') && (*s != '\n'))
-        {
-            s++;
-            len++;
-        }
-        else
-            break;
-    }
-
-    buffer_len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, NULL, 0);
-    buffer = HeapAlloc( GetProcessHeap(), 0, (buffer_len + 1) * sizeof(WCHAR));
-    len = MultiByteToWideChar(CP_OEMCP, 0, filename, len, buffer, buffer_len);
-    buffer[len] = 0;
-    DOSFS_ToDosFCBFormat(buffer, fcbW);
-    HeapFree(GetProcessHeap(), 0, buffer);
-    WideCharToMultiByte(CP_OEMCP, 0, fcbW, 12, fcb + 1, 12, NULL, NULL);
-    *fcb = 0;
-    TRACE("FCB: '%s'\n", fcb + 1);
-
-    SET_AL( context, ((strchr(filename, '*')) || (strchr(filename, '$'))) != 0 );
-
-    /* point DS:SI to first unparsed character */
-    SET_SI( context, context->Esi + (int)s - (int)filename );
-}
-
 static void INT21_GetSystemDate( CONTEXT86 *context )
 {
     SYSTEMTIME systime;
@@ -639,92 +585,6 @@
     return DRIVE_Chdir( drive, dirnameW );
 }
 
-
-static int INT21_FindFirst( CONTEXT86 *context )
-{
-    char *p;
-    const char *path;
-    DOS_FULL_NAME full_name;
-    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
-    WCHAR pathW[MAX_PATH];
-    WCHAR maskW[12];
-
-    path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
-    MultiByteToWideChar(CP_OEMCP, 0, path, -1, pathW, MAX_PATH);
-
-    dta->unixPath = NULL;
-    if (!DOSFS_GetFullName( pathW, FALSE, &full_name ))
-    {
-        SET_AX( context, GetLastError() );
-        SET_CFLAG(context);
-        return 0;
-    }
-    dta->unixPath = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
-    strcpy( dta->unixPath, full_name.long_name );
-    p = strrchr( dta->unixPath, '/' );
-    *p = '\0';
-
-    MultiByteToWideChar(CP_OEMCP, 0, p + 1, -1, pathW, MAX_PATH);
-
-    /* Note: terminating NULL in dta->mask overwrites dta->search_attr
-     *       (doesn't matter as it is set below anyway)
-     */
-    if (!DOSFS_ToDosFCBFormat( pathW, maskW ))
-    {
-        HeapFree( GetProcessHeap(), 0, dta->unixPath );
-        dta->unixPath = NULL;
-        SetLastError( ERROR_FILE_NOT_FOUND );
-        SET_AX( context, ERROR_FILE_NOT_FOUND );
-        SET_CFLAG(context);
-        return 0;
-    }
-    WideCharToMultiByte(CP_OEMCP, 0, maskW, 12, dta->mask, sizeof(dta->mask), NULL, NULL);
-    dta->drive = (path[0] && (path[1] == ':')) ? toupper(path[0]) - 'A'
-                                               : DRIVE_GetCurrentDrive();
-    dta->count = 0;
-    dta->search_attr = CL_reg(context);
-    return 1;
-}
-
-
-static int INT21_FindNext( CONTEXT86 *context )
-{
-    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
-    WIN32_FIND_DATAA entry;
-    int count;
-
-    if (!dta->unixPath) return 0;
-    if (!(count = DOSFS_FindNext( dta->unixPath, dta->mask, NULL, dta->drive,
-                                  dta->search_attr, dta->count, &entry )))
-    {
-        HeapFree( GetProcessHeap(), 0, dta->unixPath );
-        dta->unixPath = NULL;
-        return 0;
-    }
-    if ((int)dta->count + count > 0xffff)
-    {
-        WARN("Too many directory entries in %s\n", dta->unixPath );
-        HeapFree( GetProcessHeap(), 0, dta->unixPath );
-        dta->unixPath = NULL;
-        return 0;
-    }
-    dta->count += count;
-    dta->fileattr = entry.dwFileAttributes;
-    dta->filesize = entry.nFileSizeLow;
-    FileTimeToDosDateTime( &entry.ftLastWriteTime,
-                           &dta->filedate, &dta->filetime );
-    strcpy( dta->filename, entry.cAlternateFileName );
-    if (!memchr(dta->mask,'?',11)) {
-	/* wildcardless search, release resources in case no findnext will
-	 * be issued, and as a workaround in case file creation messes up
-	 * findnext, as sometimes happens with pkunzip */
-        HeapFree( GetProcessHeap(), 0, dta->unixPath );
-        dta->unixPath = NULL;
-    }
-    return 1;
-}
-
-
 static BOOL INT21_CreateTempFile( CONTEXT86 *context )
 {
     static int counter = 0;
@@ -820,99 +680,6 @@
 /* microsoft's programmers should be shot for using CP/M style int21
    calls in Windows for Workgroup's winfile.exe */
 
-static int INT21_FindFirstFCB( CONTEXT86 *context )
-{
-    BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
-    FINDFILE_FCB *pFCB;
-    LPCSTR root, cwd;
-    int drive;
-
-    if (*fcb == 0xff) pFCB = (FINDFILE_FCB *)(fcb + 7);
-    else pFCB = (FINDFILE_FCB *)fcb;
-    drive = DOS_GET_DRIVE( pFCB->drive );
-    if (!DRIVE_IsValid( drive )) return 0;
-    root = DRIVE_GetRoot( drive );
-    cwd  = DRIVE_GetUnixCwd( drive );
-    pFCB->unixPath = HeapAlloc( GetProcessHeap(), 0,
-                                strlen(root)+strlen(cwd)+2 );
-    if (!pFCB->unixPath) return 0;
-    strcpy( pFCB->unixPath, root );
-    strcat( pFCB->unixPath, "/" );
-    strcat( pFCB->unixPath, cwd );
-    pFCB->count = 0;
-    return 1;
-}
-
-
-static int INT21_FindNextFCB( CONTEXT86 *context )
-{
-    BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
-    FINDFILE_FCB *pFCB;
-    DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
-    WIN32_FIND_DATAA entry;
-    BYTE attr;
-    int count;
-
-    if (*fcb == 0xff) /* extended FCB ? */
-    {
-        attr = fcb[6];
-        pFCB = (FINDFILE_FCB *)(fcb + 7);
-    }
-    else
-    {
-        attr = 0;
-        pFCB = (FINDFILE_FCB *)fcb;
-    }
-
-    if (!pFCB->unixPath) return 0;
-    if (!(count = DOSFS_FindNext( pFCB->unixPath, pFCB->filename, NULL,
-                                  DOS_GET_DRIVE( pFCB->drive ), attr,
-                                  pFCB->count, &entry )))
-    {
-        HeapFree( GetProcessHeap(), 0, pFCB->unixPath );
-        pFCB->unixPath = NULL;
-        return 0;
-    }
-    pFCB->count += count;
-
-    if (*fcb == 0xff) { /* place extended FCB header before pResult if called with extended FCB */
-	*(BYTE *)pResult = 0xff;
-	(BYTE *)pResult +=6; /* leave reserved field behind */
-	*(BYTE *)pResult = entry.dwFileAttributes;
-	((BYTE *)pResult)++;
-    }
-    *(BYTE *)pResult = DOS_GET_DRIVE( pFCB->drive ); /* DOS_DIRENTRY_LAYOUT after current drive number */
-    ((BYTE *)pResult)++;
-    pResult->fileattr = entry.dwFileAttributes;
-    pResult->cluster  = 0;  /* what else? */
-    pResult->filesize = entry.nFileSizeLow;
-    memset( pResult->reserved, 0, sizeof(pResult->reserved) );
-    FileTimeToDosDateTime( &entry.ftLastWriteTime,
-                           &pResult->filedate, &pResult->filetime );
-
-    /* Convert file name to FCB format */
-
-    memset( pResult->filename, ' ', sizeof(pResult->filename) );
-    if (!strcmp( entry.cAlternateFileName, "." )) pResult->filename[0] = '.';
-    else if (!strcmp( entry.cAlternateFileName, ".." ))
-        pResult->filename[0] = pResult->filename[1] = '.';
-    else
-    {
-        char *p = strrchr( entry.cAlternateFileName, '.' );
-        if (p && p[1] && (p != entry.cAlternateFileName))
-        {
-            memcpy( pResult->filename, entry.cAlternateFileName,
-                    min( (p - entry.cAlternateFileName), 8 ) );
-            memcpy( pResult->filename + 8, p + 1, min( strlen(p), 3 ) );
-        }
-        else
-            memcpy( pResult->filename, entry.cAlternateFileName,
-                    min( strlen(entry.cAlternateFileName), 8 ) );
-    }
-    return 1;
-}
-
-
 static void DeleteFileFCB( CONTEXT86 *context )
 {
     FIXME("(%p): stub\n", context);
@@ -1095,20 +862,6 @@
         SET_AL( context, MAX_DOS_DRIVES );
         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 */
-        SET_AL( context, INT21_FindNextFCB(context) ? 0x00 : 0xff );
-        break;
-
     case 0x13: /* DELETE FILE USING FCB */
         DeleteFileFCB(context);
         break;
@@ -1117,10 +870,6 @@
         RenameFileFCB(context);
         break;
 
-    case 0x19: /* GET CURRENT DEFAULT DRIVE */
-        SET_AL( context, DRIVE_GetCurrentDrive() );
-        break;
-
     case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
         {
             TDB *pTask = TASK_GetCurrent();
@@ -1142,10 +891,6 @@
         GetDrivePB(context, DRIVE_GetCurrentDrive());
         break;
 
-    case 0x29: /* PARSE FILENAME INTO FCB */
-        INT21_ParseFileNameIntoFCB(context);
-        break;
-
     case 0x2a: /* GET SYSTEM DATE */
         INT21_GetSystemDate(context);
         break;
@@ -1567,12 +1312,6 @@
         bSetDOSExtendedError = (FILE_Dup2( BX_reg(context), CX_reg(context) ) == HFILE_ERROR16);
         break;
 
-    case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
-        TRACE("CWD - GET CURRENT DIRECTORY for drive %s\n",
-	      INT21_DriveName( DL_reg(context)));
-        bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
-        break;
-
     case 0x48: /* ALLOCATE MEMORY */
         TRACE("ALLOCATE MEMORY for %d paragraphs\n", BX_reg(context));
         {
@@ -1636,23 +1375,6 @@
 	}
         break;
 
-    case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
-        TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
-	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  context->SegDs, context->Edx));
-        if (!INT21_FindFirst(context)) break;
-        /* fall through */
-
-    case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
-        TRACE("FINDNEXT\n");
-        if (!INT21_FindNext(context))
-        {
-            SetLastError( ERROR_NO_MORE_FILES );
-            SET_AX( context, ERROR_NO_MORE_FILES );
-            SET_CFLAG(context);
-        }
-        else SET_AX( context, 0 );  /* OK */
-        break;
-
     case 0x54: /* Get Verify Flag */
 	TRACE("Get Verify Flag - Not Supported\n");
 	SET_AL( context, 0x00 );  /* pretend we can tell. 00h = off 01h = on */
--- dlls/winedos/int21.c.1	2002-11-27 15:36:09.000000000 +0200
+++ dlls/winedos/int21.c	2002-11-27 15:37:33.000000000 +0200
@@ -6,6 +6,7 @@
  * Copyright 1997 Andreas Mohr
  * Copyright 1998 Uwe Bonnes
  * Copyright 1998, 1999 Ove Kaaven
+ * Copyright 2002 Gyorgy 'Nog' Jeney
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -34,11 +35,578 @@
 #include "miscemu.h"
 #include "msdos.h"
 #include "file.h"
+#include "task.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(int21);
 
+/***********************************************************************
+ *             GetDosDrive [internal]
+ *
+ * returns a 0 based identifier of the dos drive passed to it.  If it is 0
+ * then it returns the current drive.
+ *
+ * PARAMS:
+ *   drive [I]: The drive to return its 0 based id.
+ *
+ * RETURNS:
+ *   Zero based drive ID.
+ */
+static int GetDosDrive(int drive)
+{
+    if(drive)
+        return drive - 1;
+    else {
+        char root[MAX_PATH];
+        GetCurrentDirectoryA(MAX_PATH, root);
+        return toupper(*root) - 'A';
+    }
+}
+
+/***********************************************************************
+ *             IsDriveValid [internal]
+ *
+ * Check to see if the 0 based drive ID passed to it is valid
+ *
+ * PARAMS:
+ *   drive [I]: Drive to check for validity.
+ *
+ * RETURNS:
+ *   0: Drive is invalid.
+ *   1: Drive is valid.
+ */
+static int IsDriveValid(int drive)
+{
+    char driveA[] = "A:\\";
+    UINT res;
+
+    *driveA += drive;
+    res = GetDriveTypeA(driveA);
+
+    if((res == DRIVE_NO_ROOT_DIR) || (res == DRIVE_UNKNOWN))
+        return 0;
+
+    return 1;
+}
+
+/* Many calls translate a drive argument like this:
+ * drive number (00h = default, 01h = A:, etc)
+ */
+static char drivestring[] = "default";
+
+/***********************************************************************
+ *             INT21_DriveName [internal]
+ *
+ * Returns a string which displays the drive in drive.  If drive is 0 then
+ * is means 'default' dirve.
+ *
+ * PARAMS:
+ *   drive [I]: Drive to return a string for.
+ *
+ * RETURNS:
+ *   Null trminated character string which displays the drive.
+ */
+char *INT21_DriveName(int drive)
+{
+    if(drive > 0) {
+        drivestring[0] = (unsigned char)drive + '@';
+        drivestring[1] = ':';
+        drivestring[2] = 0;
+    }
+    return drivestring;
+}
+
+/***********************************************************************
+ *             INT21_GetCurrentDirectory [internal]
+ *
+ * Returns the current directory for a given drive.
+ *
+ * PARAMS:
+ *   ptr [O]: Pointer to a buffer to hold the directory.
+ *   driveg [I]: Drive who's current directory is to be retrieved.
+ *
+ * RETURNS:
+ *   TRUE: Sucessful.
+ *   FALSE: Failure.
+ *
+ * NOTES:
+ *   Mabe we should check if the directory is a valid dos directory name.
+ */
+static BOOL INT21_GetCurrentDirectory(char *ptr, int driveg)
+{
+    int drive = GetDosDrive(driveg);
+    int defdrive = GetDosDrive(0);
+    char curdir[66];
+
+    if(!IsDriveValid(drive)) {
+        SetLastError(ERROR_INVALID_DRIVE);
+        return FALSE;
+    }
+
+    if(defdrive != drive) {
+        char driveA[] = "a:";
+        *driveA += drive;
+        SetCurrentDirectoryA(driveA);
+    }
+
+    if(GetCurrentDirectoryA(66, curdir))
+        strcpy(ptr, curdir + 3);
+
+    if(defdrive != drive) {
+        char driveA[] = "a:";
+        *driveA += defdrive;
+        SetCurrentDirectoryA(driveA);
+    }
+
+    ptr[63] = 0; /* ensure 0 termination */
+
+    TRACE("Current directory in drive %d is %s\n", drive, ptr);
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *                 GetCurrentDTA [internal]
+ *
+ * Returns a pointer to the current DTA.
+ *
+ * PARAMS:
+ *   context [I]: Pointer to structure holding registers.
+ *
+ * RETURNS:
+ *   Pointer to the current DTA.
+ */
+static BYTE *GetCurrentDTA(CONTEXT86 *context)
+{
+    TDB *pTask = GlobalLock16(GetCurrentTask());
+
+    return (BYTE *)CTX_SEG_OFF_TO_LIN(context, SELECTOROF(pTask->dta),
+                                                (DWORD)OFFSETOF(pTask->dta));
+}
+
+/***********************************************************************
+ *                  INT21_ParseToFCB [internal]
+ *
+ * Parses a filename to a valid FCB file name according to pcontrol.
+ *
+ * PARAMS:
+ *   file [I]: Valid Dos filename.
+ *   fcb [O]: Pointer to buffer to hold FCB
+ *   pcontrol [I]: What to do if there are filename bits missing.
+ *   drive [O]: The drive that is mentioned in the filename.
+ *   unparsed [O]: Location of the first unparsed char relative to the filename. *
+ * RETURNS:
+ *   TRUE: There are wild cards in the filename.
+ *   FALSE: There are no wild cards in the filename.
+ *
+ * NOTES:
+ *   This code could be cleaned up some more.
+ */
+static BOOL INT21_ParseToFCB(const char *file, char *fcb, BYTE pcontrol,
+                             int *drive, int *unparsed)
+{
+    int len = 0;
+    const char *lastback = NULL;
+    BOOL ext = FALSE;
+    BOOL wild = FALSE;
+    char nfcb[12];
+
+    TRACE("filename: %s control: %02x\n", file, pcontrol);
+
+    while(file[len] && (file[len] != ' ') && (file[len] != '\r') &&
+          (file[len] != '\n')) {
+        if(file[len] == '\\')
+            lastback = &file[len + 1];
+        len++;
+    }
+
+    /* Check to see if a drive was specified */
+    if(lastback && (*file != '\\')) {
+        /* There was a drive specified */
+        if(drive) *drive = 'A' - toupper(*file);
+    } else {
+        /* Drive was not specified, see if we set the drive to zero or not */
+        if(!(pcontrol & 0x2))
+            if(drive) *drive = 0;
+    }
+
+    if(!lastback) lastback = file;
+
+    if(*lastback == '.') {
+        /* There is no filename specified */
+        if(!(pcontrol & 0x4)) /* Fill filename space with spaces */
+            memset(fcb, ' ', 8);
+        len = 8;
+        lastback++;
+        ext = TRUE;
+    } else
+        len = 0;
+
+    for(; *lastback && (*lastback != ' ') && (*lastback != '\r') &&
+         (*lastback != '\n'); lastback++, len++) {
+        if(len == 12)
+            break;
+
+        switch(*lastback) {
+        case '.':
+            /* Pad the filname with spaces */
+            if(ext) {
+                TRACE("Illeagel filename, it has more than one extension\n");
+                len = 11;
+            } else {
+                memset(&fcb[len], ' ', 8 - len);
+                len = 7; /* the for construct will increment it */
+                ext = TRUE;
+            }
+            break;
+        case '*':
+            wild = TRUE;
+            /* Pad the rest of the filename with ?s */
+            if(ext) {
+                memset(&fcb[len], '?', 11 - len);
+                len = 11;
+            } else
+                memset(&fcb[len], '?', 8 - len);
+            break;
+        case '?':
+            wild = TRUE;
+            /* fall through */
+        default:
+            fcb[len] = toupper(*lastback);
+        }
+    }
+
+    if(!ext && (len == 8)) {
+        /* check to see what we should do if there is no extension */
+        if(!(pcontrol & 0x8))
+            memset(fcb + 8, ' ', 3);
+    } else if(len < 11)
+        /* pad the fcb extension with spaces */
+        memset(fcb + len, ' ', 11 - len);
+
+    memcpy(nfcb, fcb, 11);
+
+    nfcb[11] = 0;
+
+    TRACE("FCB: %s\n", nfcb);
+
+    if(unparsed) *unparsed = lastback - file;
+
+    return wild;
+}
+
+/***********************************************************************
+ *                  INT21_FCBToFile [internal]
+ *
+ * Parses an FCB filename back to a normal filename.
+ *
+ * PARAMS:
+ *   dest [O]: Pointer to buffer to hold filename.
+ *   fcb [I]: FCB filename to parse.
+ *
+ * RETURNS:
+ *   Nothing.
+ */
+static void INT21_FCBToFile(char *dest, char *fcb)
+{
+    int n;
+
+    TRACE("FCB: %s\n", fcb);
+
+    for(n = 0; n < 11; n++, fcb++, dest++) {
+        if(n == 8) {
+           *dest = '.';
+           dest++;
+        }
+
+        if(*fcb != ' ')
+            *dest = *fcb;
+    }
+
+    *dest = 0;
+
+    TRACE("Filname: %s\n", dest);
+}
+
+/***********************************************************************
+ *                  INT21_NextFile [internal]
+ *
+ * Helper function for Find{First|Next}{File|FCB}.  Check to see if the
+ * attributes match and copies the relevent information from entry to
+ * to buffers.
+ *
+ * PARAMS:
+ *   entry [I]: Pointer to a valid WIN32_FIND_DATAA as returned by
+ *              Find{First|Next}FileA.
+ *   file [O]: Pointer to a buffer to hold the filename.
+ *   attr [O]: Pointer to a buffer to hold the attributes of the file.
+ *   data [O]: Pointer to a buffer to hold the last acess date of the file.
+ *   time [O]: Pointer to a buffer to hold the last acess time of the file.
+ *   size [O]: Pointer to a buffer to hold the size of the file.
+ *   findattr [I]: The search attributes.
+ *
+ * RETURNS:
+ *   0: Attributes don't match.
+ *   1: Attributes match.
+ */
+static int INT21_NextFile(WIN32_FIND_DATAA *entry, char *file, BYTE *attr,
+                          WORD *date, WORD *time, DWORD *size, BYTE findattr)
+{
+    TRACE("Attribute of found file: 0x%lx, find attributes: 0x%x\n",
+          entry->dwFileAttributes & 0x3f, findattr);
+
+    if((findattr & entry->dwFileAttributes & 0x3f)) {
+        *attr = entry->dwFileAttributes;
+        FileTimeToDosDateTime(&entry->ftLastWriteTime, date, time);
+        *size = entry->nFileSizeLow;
+        strcpy(file, entry->cAlternateFileName);
+        TRACE("Search attributes match, returning %s\n", file);
+        return 1;
+    }
+
+    *file = 0;
+    return 0;
+}
+
+/***********************************************************************
+ *                   INT21_FindFirst [internal]
+ *
+ * Implementation of the find fisrt function (0x4e).
+ *
+ * PARAMS:
+ *   context [I]: Pointer to structure holding registers.
+ *
+ * RETURNS:
+ *   0: Failure.
+ *   1: Success.
+ */
+static int INT21_FindFirst(CONTEXT86 *context)
+{
+    const char *path;
+    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
+    int count = 0;
+    WIN32_FIND_DATAA entry;
+
+    path = (const char *)CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+                                            context->Edx);
+
+    /* Fill in the DTA */
+    INT21_ParseToFCB(path, dta->mask, 0, NULL, NULL);
+    dta->search_attr = CX_reg(context);
+    if(!dta->search_attr) {
+        /* If attributes are 0 then we are to find files that have no attributes         * set, but since dos doesn't treat it this way, we won't.  Dos treets
+         * it as find archive */
+        dta->search_attr = 0x20;
+    }
+    dta->count = 0;
+    dta->cluster = 0; /* What are we meant to do here ?? */
+    dta->drive = GetDosDrive(0);
+    *dta->filename = 0;
+
+    if((dta->handle = FindFirstFileA(path, &entry)) == INVALID_HANDLE_VALUE)
+        return 0;
+
+findagain:
+
+    if(!INT21_NextFile(&entry, dta->filename, &dta->fileattr, &dta->filedate,
+                       &dta->filetime, &dta->filesize, dta->search_attr)) {
+        /* Continue searching */
+        if(FindNextFileA(dta->handle, &entry)) {
+            count++;
+            goto findagain;
+        } else {
+            FindClose(dta->handle);
+            TRACE("No matching files found\n");
+            return 0;
+        }
+    }
+
+    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 */
+        FindClose(dta->handle);
+    }
+
+    return 1;
+}
+
+/***********************************************************************
+ *                    INT21_FindNext [internal]
+ *
+ * Implementation of FindNext file function (0x4f).
+ *
+ * PARAMS:
+ *   context [I]: Pointer to structure holding registers.
+ *
+ * RETURNS:
+ *   0: Failure.
+ *   1: Sucess.
+ */
+static int INT21_FindNext(CONTEXT86 *context)
+{
+    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
+    WIN32_FIND_DATAA entry;
+    int count = dta->count;
+
+    for(;; ++count) {
+        if(FindNextFileA(dta->handle, &entry)) {
+            if(!INT21_NextFile(&entry, dta->filename, &dta->fileattr,
+                               &dta->filedate, &dta->filetime, &dta->filesize,
+                               dta->search_attr)) {
+                FindClose(dta->handle);
+                return 0;
+            } else
+                dta->count = count;
+        } else {
+            TRACE("No more matching files found\n");
+            *dta->filename = 0;
+            FindClose(dta->handle);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+/***********************************************************************
+ *                    INT21_FindFirstFCB [internal]
+ *
+ * Implementation of Find First using FCB.
+ *
+ * PARAMS:
+ *   context [I]: Pointer to structure holding registers.
+ *
+ * RETURNS:
+ *   0: No file found.
+ *   1: Files found.
+ */
+static int INT21_FindFirstFCB(CONTEXT86 *context)
+{
+    FINDFILE_FCB *fcb;
+    BYTE *efcb = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
+    char path[MAX_PATH];
+    HANDLE findh;
+    WIN32_FIND_DATAA entry;
+    DOS_DIRENTRY_LAYOUT *dta = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
+    int attr = 0;
+
+    if(*efcb == 0xff) {
+       fcb = (FINDFILE_FCB *)(efcb + 7);
+       attr = efcb[6];
+    } else fcb = (FINDFILE_FCB *)efcb;
+
+    if(!INT21_GetCurrentDirectory(path, fcb->drive))
+        return 0;
+
+    memmove(path + 3, path, 63);
+    memcpy(path, "A:\\", 3);
+    *path += GetDosDrive(fcb->drive);
+
+    INT21_FCBToFile(&path[strlen(path) + 1], fcb->filename);
+
+    if((findh = FindFirstFileA(path, &entry)) == INVALID_HANDLE_VALUE)
+        return 0;
+
+findagain:
+
+    if(*efcb == 0xff) {
+        *(BYTE *)dta = 0xff;
+        (BYTE *)dta += 7; /* Place the extended FCB header first */
+    }
+
+    /* DOS_DIRENTRY_LAYOUT after current drive number */
+    *(BYTE *)dta = GetDosDrive(fcb->drive);
+    ((BYTE *)dta)++;
+
+    if(!INT21_NextFile(&entry, path, &dta->fileattr, &dta->filedate,
+                       &dta->filetime, &dta->filesize, attr)) {
+        /* Continue searching */
+        if(FindNextFileA(fcb->findh, &entry)) {
+            goto findagain;
+        } else {
+            TRACE("No more file found\n");
+            FindClose(findh);
+            return 0;
+        }
+    }
+
+    INT21_ParseToFCB(path, dta->filename, 0, NULL, NULL);
+
+    if(*efcb == 0xff) {
+        ((BYTE *)dta)--;
+        *(BYTE *)dta = entry.dwFileAttributes;
+    }
+
+    if (!memchr(fcb->filename, '?', 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 */
+        FindClose(findh);
+    }
+
+    return 1;
+}
+
+/***********************************************************************
+ *                    INT21_FindNextFCB [internal]
+ *
+ * Implementation of FindNextFCB.
+ *
+ * PARAMS:
+ *   context [I]: Pointer to structure holding registers.
+ *
+ * RETURNS:
+ *   0: No files found.
+ *   1: Files found.
+ */
+static int INT21_FindNextFCB(CONTEXT86 *context)
+{
+    FINDFILE_FCB *fcb;
+    BYTE *efcb = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
+    WIN32_FIND_DATAA entry;
+    DOS_DIRENTRY_LAYOUT *dta = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
+    int attr = 0;
+    char file[MAX_PATH];
+
+    if(*efcb == 0xff) {
+       fcb = (FINDFILE_FCB *)(efcb + 7);
+       attr = efcb[6];
+    } else fcb = (FINDFILE_FCB *)efcb;
+
+    if(*efcb == 0xff) {
+        *(BYTE *)dta = 0xff;
+        (BYTE *)dta += 7; /* Place the extended FCB header first */
+    }
+
+    /* DOS_DIRENTRY_LAYOUT after current drive number */
+    *(BYTE *)dta = GetDosDrive(fcb->drive);
+    ((BYTE *)dta)++;
+
+    for(;;) {
+        if(FindNextFileA(fcb->findh, &entry)) {
+            if(INT21_NextFile(&entry, file, &dta->fileattr, &dta->filedate,
+                               &dta->filetime, &dta->filesize, attr))
+                break;
+        /* Continue searching */
+        } else {
+            TRACE("No more file found\n");
+            FindClose(fcb->findh);
+            return 0;
+        }
+    }
+
+    INT21_ParseToFCB(file, dta->filename, 0, NULL, NULL);
+
+    if(*efcb == 0xff) {
+        ((BYTE *)dta)--;
+        *(BYTE *)dta = entry.dwFileAttributes;
+    }
+
+    return 1;
+}
+
 void WINAPI DOSVM_Int21Handler_Ioctl( CONTEXT86 *context )
 {
   static const WCHAR emmxxxx0W[] = {'E','M','M','X','X','X','X','0',0};
@@ -293,6 +861,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));
+        SET_AL(context, INT21_FindFirstFCB(context) ? 0x00 : 0xff);
+        break;
+
+    case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
+        SET_AL(context, INT21_FindNextFCB(context) ? 0x00 : 0xff);
+        break;
+
+    case 0x19: /* GET CURRENT DEFAULT DRIVE */
+        SET_AL(context, GetDosDrive(0));
+        break;
+
     case 0x25: /* SET INTERRUPT VECTOR */
         if(DOSVM_IsWin16()) DOSVM_SetPMHandler16(AL_reg(context),
                                        (FARPROC16)MAKESEGPTR(context->SegDs,
@@ -302,6 +884,21 @@
                                                       DX_reg(context)));
         break;
 
+    case 0x29: /* PARSE FILENAME INTO FCB */
+        {
+            FINDFILE_FCB *fcb = CTX_SEG_OFF_TO_LIN(context, context->SegEs,
+                                                   context->Edi);
+            int unp;
+            if(INT21_ParseToFCB(CTX_SEG_OFF_TO_LIN(context, context->SegDs,
+                                                   context->Esi), fcb->filename,                                AL_reg(context), (int *)&fcb->drive, &unp))
+                SET_AL(context, 1);
+            else
+                SET_AL(context, 0);
+
+            SET_SI(context, context->Esi + unp);
+        }
+        break;
+
     case 0x35: /* GET INTERRUPT VECTOR */
         {
             FARPROC16 addr;
@@ -333,6 +930,16 @@
         DOSVM_Int21Handler_Ioctl( context );
         break;
 
+    case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
+        TRACE("CWD - GET CURRENT DIRECTORY for %s drive\n",
+              INT21_DriveName(DL_reg(context)));
+        if(!(bSetDOSExtendedError = !INT21_GetCurrentDirectory(
+                                      (char *)CTX_SEG_OFF_TO_LIN(context,
+                                                                 context->SegDs,                                                                 context->Esi),
+                                      DL_reg(context))))
+            SET_AX(context, 0x0100); /* success return code */
+        break;
+
     case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
         TRACE("EXEC %s\n", (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,
               context->Edx));
@@ -362,6 +969,24 @@
         DOSVM_retval = 0;
         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)) {
+            SetLastError(ERROR_NO_MORE_FILES);
+            bSetDOSExtendedError = TRUE;
+        }
+        break;
+
+    case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
+        TRACE("FINDNEXT\n");
+        if(!INT21_FindNext(context))
+        {
+            SetLastError(ERROR_NO_MORE_FILES);
+            bSetDOSExtendedError = TRUE;
+        }
+        else SET_AX(context, 0);  /* OK */
+        break;
+
     case 0x50: /* SET CURRENT PROCESS ID (SET PSP ADDRESS) */
         TRACE("SET CURRENT PROCESS ID (SET PSP ADDRESS)\n");
         DOSVM_psp = BX_reg(context);
--- ../readwritewine/include/msdos.h	2002-06-01 01:06:48.000000000 +0200
+++ include/msdos.h	2002-11-27 15:36:23.000000000 +0200
@@ -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  *handle;       /* 11 windows find handle (was: reserved) */
     BYTE   fileattr;     /* 15 file attributes */
     WORD   filetime;     /* 16 file time */
     WORD   filedate;     /* 18 file date */
@@ -57,8 +57,8 @@
 {
     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) */
+    int    reserved;             /* 0c reserved */
+    void  *findh;                /* 10 windows find handle (was: reserved) */
 } FINDFILE_FCB;
 
 /* DOS directory entry for FindFirstFCB/FindNextFCB */
--- ../readwritewine/files/dos_fs.c	2002-11-21 09:37:00.000000000 +0200
+++ files/dos_fs.c	2002-11-27 15:36:23.000000000 +0200
@@ -1808,99 +1808,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. Thus, we should own the Win16Mutex anyway.
- *       Nevertheless, we explicitly enter it to ensure the static
- *       directory cache is protected.
- */
-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);
-
-    _EnterWin16Lock();
-
-    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( DRIVE_GetCodepage(drive), 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) );
-    }
-
-    _LeaveWin16Lock();
-
-    return count;
-}
-
 /*************************************************************************
  *           FindFirstFileExW  (KERNEL32.@)
  */
--- ../readwritewine/include/file.h	2002-11-24 03:18:29.000000000 +0200
+++ include/file.h	2002-11-27 15:36:23.000000000 +0200
@@ -104,9 +104,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 );
 
 /* profile.c */
 extern void PROFILE_UsageWineIni(void);



More information about the wine-devel mailing list