> 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.
--- ../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.@) */