--- 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);