int21 find move

György 'Nog' Jeney nog at sdf.lonestar.org
Sat Jan 18 09:35:52 CST 2003


> I hope that at least this section of my attempt at the int21  move is
> acceptable.  I have revised the code a little to use seemingly simpler
> constructs.
>
> ChangeLog:
>  * dlls/winedos/int21.c
>  * msdos/int21.c
>  * include/file.h
>  * include/msdos.h
>  * files/dos_fs.c
>    Move Find functions and FCB parsing functions to winedos.
>

I've sent this patch quite a wile ago and it still hasn't been commited
and I didn't see any comments on it. Is there any reason for this?

nog.

-------------- next part --------------
--- ../cleanwine/msdos/int21.c	2002-12-11 08:17:20.000000000 +0200
+++ msdos/int21.c	2002-12-12 10:05:43.000000000 +0200
@@ -154,15 +154,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 */
@@ -419,50 +410,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 );
-}
-
 
 /* Many calls translate a drive argument like this:
    drive number (00h = default, 01h = A:, etc)
@@ -619,91 +566,6 @@
 }
 
 
-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 = ' ';
-
-    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;
@@ -784,99 +646,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);
@@ -1019,20 +788,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;
@@ -1066,10 +821,6 @@
         GetDrivePB(context, DRIVE_GetCurrentDrive());
         break;
 
-    case 0x29: /* PARSE FILENAME INTO FCB */
-        INT21_ParseFileNameIntoFCB(context);
-        break;
-
     case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
         TRACE("GET DISK TRANSFER AREA ADDRESS\n");
         {
@@ -1483,23 +1234,6 @@
         if (AX_reg(context) < 32) SET_CFLAG(context);
         break;
 
-    case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
-        TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
-	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  context->SegDs, context->Edx));
-        if (!INT21_FindFirst(context)) break;
-        /* fall through */
-
-    case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
-        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 0x56: /* "RENAME" - RENAME FILE */
         TRACE("RENAME %s to %s\n",
 	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx),
--- ../cleanwine/include/file.h	2002-11-24 03:18:29.000000000 +0200
+++ include/file.h	2002-12-12 10:37:32.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);
--- ../cleanwine/include/msdos.h	2002-12-10 19:04:30.000000000 +0200
+++ include/msdos.h	2002-12-12 10:08:08.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 */
--- ../cleanwine/dlls/winedos/int21.c	2002-12-11 08:17:13.000000000 +0200
+++ dlls/winedos/int21.c	2002-12-12 13:01:20.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
@@ -33,6 +34,7 @@
 #include "msdos.h"
 #include "file.h"
 #include "winerror.h"
+#include "task.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
 
@@ -389,6 +391,531 @@
 
 
 /***********************************************************************
+ *           INT21_GetDosDrive
+ *
+ * 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 whose 0 based id to return.
+ *
+ * RETURNS:
+ *   Zero based drive ID.
+ */
+static int INT21_GetDosDrive(int drive)
+{
+    if (drive)
+        return drive - 1;
+    else {
+        char root[MAX_PATH];
+        GetCurrentDirectoryA( MAX_PATH, root );
+        return toupper( *root ) - 'A';
+    }
+}
+
+
+/***********************************************************************
+ *           INT21_IsDriveValid
+ *
+ * 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 INT21_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;
+}
+
+
+/***********************************************************************
+ *           INT21_GetCurrentDirectory
+ *
+ * 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 = INT21_GetDosDrive(driveg);
+    int defdrive = INT21_GetDosDrive(0);
+    char curdir[MAX_PATH];
+
+    if (!INT21_IsDriveValid(drive)) {
+        SetLastError(ERROR_INVALID_DRIVE);
+        return FALSE;
+    }
+
+    if (defdrive != drive) {
+        char driveA[] = "a:";
+        *driveA += drive;
+        SetCurrentDirectoryA( driveA );
+    }
+
+    if (GetCurrentDirectoryA( MAX_PATH, curdir )) {
+        GetShortPathNameA( curdir, ptr, 63 );
+        /* remove the drive previx */
+        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;
+}
+
+
+/***********************************************************************
+ *           INT21_GetCurrentDTA
+ *
+ * Returns a pointer to the current DTA.
+ */
+static BYTE *INT21_GetCurrentDTA(CONTEXT86 * context)
+{
+    TDB *pTask = GlobalLock16( GetCurrentTask() );
+
+    return (BYTE *) CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta),
+                                       (DWORD) OFFSETOF(pTask->dta) );
+}
+
+
+/***********************************************************************
+ *           INT21_ParseToFCB
+ *
+ * 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.
+ */
+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) {
+        /* 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
+ *
+ * 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
+ *
+ * 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
+ *
+ * Implementation of the find fisrt function (0x4e).
+ */
+static int INT21_FindFirst(CONTEXT86 * context)
+{
+    const char *path;
+    FINDFILE_DTA *dta = (FINDFILE_DTA *)INT21_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 = INT21_GetDosDrive(0);
+    *dta->filename = 0;
+
+    if ((dta->handle = FindFirstFileA(path, &entry)) == INVALID_HANDLE_VALUE)
+        return 0;
+
+    /* Loop until we find a file that matches the search attributes */
+    for(;; count++) {
+        if (!INT21_NextFile( &entry, dta->filename, &dta->fileattr,
+                             &dta->filedate, &dta->filetime, &dta->filesize,
+                             dta->search_attr )) {
+            /* Continue searching */
+            if (!FindNextFileA( dta->handle, &entry )) {
+                FindClose( dta->handle );
+                TRACE( "No matching files found\n" );
+                return 0;
+            }
+        } else
+            break;
+    }
+
+    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
+ *
+ * Implementation of FindNext file function (0x4f).
+ */
+static int INT21_FindNext(CONTEXT86 * context)
+{
+    FINDFILE_DTA *dta = (FINDFILE_DTA *)INT21_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 ))
+                return 1;
+        } else {
+            TRACE( "No more matching files found\n" );
+            *dta->filename = 0;
+            FindClose( dta->handle );
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+
+/***********************************************************************
+ *           INT21_FindFirstFCB
+ *
+ * Implementation of Find First using FCB.
+ */
+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 *)INT21_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 += INT21_GetDosDrive( fcb->drive );
+
+    INT21_FCBToFile( &path[strlen(path) + 1], fcb->filename );
+
+    if ((findh = FindFirstFileA( path, &entry )) == INVALID_HANDLE_VALUE)
+        return 0;
+
+    if (*efcb == 0xff) {
+        *(BYTE *)dta = 0xff;
+        (BYTE *)dta += 7;  /* Place the extended FCB header first */
+    }
+
+    /* DOS_DIRENTRY_LAYOUT after current drive number */
+    *(BYTE *) dta = INT21_GetDosDrive( fcb->drive );
+    ((BYTE *) dta)++;
+
+    for(;;) {
+        if (INT21_NextFile(&entry, path, &dta->fileattr, &dta->filedate,
+                           &dta->filetime, &dta->filesize, attr)) {
+            INT21_ParseToFCB( path, dta->filename, 0, NULL, NULL );
+
+            if (*efcb == 0xff) {
+                ((BYTE *) dta)--;
+                *(BYTE *) dta = entry.dwFileAttributes;
+            }
+
+            break;
+        } else {
+            /* Continue searching */
+            if (!FindNextFileA( fcb->findh, &entry )) {
+                TRACE( "No more file found\n" );
+                FindClose( findh );
+                return 0;
+            }
+        }
+    }
+
+    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
+ *
+ * Implementation of FindNextFCB.
+ */
+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 *) INT21_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 = INT21_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;
+}
+
+
+/***********************************************************************
  *           INT21_Ioctl
  *
  * Handler for function 0x44.
@@ -705,7 +1232,15 @@
         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 0x13: /* DELETE FILE USING FCB */
         INT_Int21Handler( context );
         break;
@@ -769,7 +1304,19 @@
         break;
 
     case 0x29: /* PARSE FILENAME INTO FCB */
-        INT_Int21Handler( context );
+        {
+            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 0x2a: /* GET SYSTEM DATE */
@@ -993,8 +1540,21 @@
         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 */
-        INT_Int21Handler( context );
+        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) */
--- ../cleanwine/files/dos_fs.c	2002-12-14 07:54:56.000000000 +0200
+++ files/dos_fs.c	2002-12-18 15:51:11.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, ' ', sizeof(info) );
-    }
-
-    _LeaveWin16Lock();
-
-    return count;
-}
-
 /*************************************************************************
  *           FindFirstFileExW  (KERNEL32.@)
  */




More information about the wine-patches mailing list