Mike McCormack a écrit :
This closes bug 521, and removes a couple of wine_todos from the regression test for pathes. The test for setting "lastpart" in both GetFullPathNameA/W was wrong (would always pass).
for the record, I also sent a patch regarding (among other things) this issue, which also has never been applied. I don't know Alexandre's state on this. A+
Eric Pouech pouech-eric@wanadoo.fr writes:
Mike McCormack a écrit :
This closes bug 521, and removes a couple of wine_todos from the regression test for pathes. The test for setting "lastpart" in both GetFullPathNameA/W was wrong (would always pass).
for the record, I also sent a patch regarding (among other things) this issue, which also has never been applied. I don't know Alexandre's state on this.
Hmm I don't remember that one, it may have gotten lost in the vacation backlog. Could you please resend?
Hmm I don't remember that one, it may have gotten lost in the vacation backlog. Could you please resend?
here we go A+
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/Makefile.in dlls/kernel/Makefile.in --- dlls/kernel38/Makefile.in 2003-12-06 16:09:08.000000000 +0100 +++ dlls/kernel/Makefile.in 2003-12-12 21:33:31.000000000 +0100 @@ -51,6 +51,7 @@ module.c \ ne_module.c \ ne_segment.c \ + path.c \ powermgnt.c \ process.c \ profile.c \ diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/path.c dlls/kernel/path.c --- dlls/kernel38/path.c 1970-01-01 01:00:00.000000000 +0100 +++ dlls/kernel/path.c 2003-12-13 10:30:11.000000000 +0100 @@ -0,0 +1,440 @@ +/* + * File handling functions + * + * Copyright 1993 Erik Bos + * Copyright 1996 Alexandre Julliard + * Copyright 2003 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "winerror.h" +#include "ntstatus.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "wincon.h" +#include "wine/winbase16.h" +#include "kernel_private.h" + +#include "wine/unicode.h" +#include "wine/debug.h" +#include "async.h" + +WINE_DEFAULT_DEBUG_CHANNEL(file); + +#define MAX_PATHNAME_LEN 1024 + + +/*********************************************************************** + * GetFullPathNameW (KERNEL32.@) + * NOTES + * if the path closed with '', *lastpart is 0 + */ +DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, + LPWSTR *lastpart ) +{ + LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(buffer)); + DWORD ret; + + if (!dst) return 0; + ret = RtlGetFullPathName_U(name, len * sizeof(WCHAR), dst, lastpart) / sizeof(WCHAR); + if (ret < len) + { + strcpyW(buffer, dst); + if (lastpart && *lastpart) *lastpart = buffer + (*lastpart - dst); + } + HeapFree(GetProcessHeap(), 0, dst); + return ret; +} + +/*********************************************************************** + * GetFullPathNameA (KERNEL32.@) + * NOTES + * if the path closed with '', *lastpart is 0 + */ +DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, + LPSTR *lastpart ) +{ + UNICODE_STRING nameW; + WCHAR bufferW[MAX_PATH]; + DWORD ret, retW; + + if (!name) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + + retW = GetFullPathNameW( nameW.Buffer, MAX_PATH, bufferW, NULL); + + if (!retW) + ret = 0; + else if (retW > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + ret = 0; + } + else + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); + if (ret && ret <= len) + { + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, len, NULL, NULL); + ret--; /* length without 0 */ + + if (lastpart) + { + LPSTR p = buffer + strlen(buffer) - 1; + + if (*p != '\') + { + while ((p > buffer + 2) && (*p != '\')) p--; + *lastpart = p + 1; + } + else *lastpart = NULL; + } + } + } + + RtlFreeUnicodeString(&nameW); + return ret; +} + + +/*********************************************************************** + * GetLongPathNameW (KERNEL32.@) + * + * NOTES + * observed (Win2000): + * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 + * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 + */ +DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) +{ + WCHAR tmplongpath[MAX_PATHNAME_LEN]; + LPCWSTR p; + DWORD sp = 0, lp = 0; + DWORD tmplen; + BOOL unixabsolute = (shortpath[0] == '/'); + WIN32_FIND_DATAW wfd; + HANDLE goit; + + if (!shortpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + if (!shortpath[0]) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return 0; + } + + TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen); + + if (shortpath[0] == '\' && shortpath[1] == '\') + { + ERR("UNC pathname %s\n", debugstr_w(shortpath)); + lstrcpynW( longpath, shortpath, longlen ); + return strlenW(longpath); + } + + /* check for drive letter */ + if (!unixabsolute && shortpath[1] == ':' ) + { + tmplongpath[0] = shortpath[0]; + tmplongpath[1] = ':'; + lp = sp = 2; + } + + while (shortpath[sp]) + { + /* check for path delimiters and reproduce them */ + if (shortpath[sp] == '\' || shortpath[sp] == '/') + { + if (!lp || tmplongpath[lp-1] != '\') + { + /* strip double "\" */ + tmplongpath[lp++] = '\'; + } + tmplongpath[lp] = 0; /* terminate string */ + sp++; + continue; + } + + p = shortpath + sp; + if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\')) + { + tmplongpath[lp++] = *p++; + tmplongpath[lp++] = *p++; + } + for (; *p && *p != '/' && *p != '\'; p++); + tmplen = p - (shortpath + sp); + lstrcpynW(tmplongpath + lp, shortpath + sp, tmplen + 1); + /* Check if the file exists and use the existing file name */ + goit = FindFirstFileW(tmplongpath, &wfd); + if (goit == INVALID_HANDLE_VALUE) + { + TRACE("not found %s!\n", debugstr_w(tmplongpath)); + SetLastError ( ERROR_FILE_NOT_FOUND ); + return 0; + } + FindClose(goit); + strcpyW(tmplongpath + lp, wfd.cFileName); + lp += strlenW(tmplongpath + lp); + sp += tmplen; + } + tmplen = strlenW(shortpath) - 1; + if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\') && + (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\')) + tmplongpath[lp++] = shortpath[tmplen]; + tmplongpath[lp] = 0; + + tmplen = strlenW(tmplongpath) + 1; + if (tmplen <= longlen) + { + strcpyW(longpath, tmplongpath); + TRACE("returning %s\n", debugstr_w(longpath)); + tmplen--; /* length without 0 */ + } + + return tmplen; +} + +/*********************************************************************** + * GetLongPathNameA (KERNEL32.@) + */ +DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen ) +{ + UNICODE_STRING shortpathW; + WCHAR longpathW[MAX_PATH]; + DWORD ret, retW; + + if (!shortpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + TRACE("%s\n", debugstr_a(shortpath)); + + if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW, shortpath)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + + retW = GetLongPathNameW(shortpathW.Buffer, longpathW, MAX_PATH); + + if (!retW) + ret = 0; + else if (retW > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + ret = 0; + } + else + { + ret = WideCharToMultiByte(CP_ACP, 0, longpathW, -1, NULL, 0, NULL, NULL); + if (ret <= longlen) + { + WideCharToMultiByte(CP_ACP, 0, longpathW, -1, longpath, longlen, NULL, NULL); + ret--; /* length without 0 */ + } + } + + RtlFreeUnicodeString(&shortpathW); + return ret; +} + + +/*********************************************************************** + * GetShortPathNameW (KERNEL32.@) + * + * NOTES + * observed: + * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 + * longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0 + * + * more observations ( with NT 3.51 (WinDD) ): + * longpath <= 8.3 -> just copy longpath to shortpath + * longpath > 8.3 -> + * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND + * b) file does exist -> set the short filename. + * - trailing slashes are reproduced in the short name, even if the + * file is not a directory + * - the absolute/relative path of the short name is reproduced like found + * in the long name + * - longpath and shortpath may have the same address + * Peter Ganten, 1999 + */ +DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen ) +{ + WCHAR tmpshortpath[MAX_PATHNAME_LEN]; + LPCWSTR p; + DWORD sp = 0, lp = 0; + DWORD tmplen; + BOOL unixabsolute = (longpath[0] == '/'); + WIN32_FIND_DATAW wfd; + HANDLE goit; + UNICODE_STRING ustr; + WCHAR ustr_buf[8+1+3+1]; + + TRACE("%s\n", debugstr_w(longpath)); + + if (!longpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + if (!longpath[0]) + { + SetLastError(ERROR_BAD_PATHNAME); + return 0; + } + + /* check for drive letter */ + if (!unixabsolute && longpath[1] == ':' ) + { + tmpshortpath[0] = longpath[0]; + tmpshortpath[1] = ':'; + sp = lp = 2; + } + + ustr.Buffer = ustr_buf; + ustr.Length = 0; + ustr.MaximumLength = sizeof(ustr_buf); + + while (longpath[lp]) + { + /* check for path delimiters and reproduce them */ + if (longpath[lp] == '\' || longpath[lp] == '/') + { + if (!sp || tmpshortpath[sp-1] != '\') + { + /* strip double "\" */ + tmpshortpath[sp] = '\'; + sp++; + } + tmpshortpath[sp] = 0; /* terminate string */ + lp++; + continue; + } + + for (p = longpath + lp; *p && *p != '/' && *p != '\'; p++); + tmplen = p - (longpath + lp); + lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1); + if (tmplen <= 8+1+3+1) + { + memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR)); + ustr_buf[tmplen] = '\0'; + ustr.Length = tmplen * sizeof(WCHAR); + /* Check, if the current element is a valid dos name */ + if (!RtlIsNameLegalDOS8Dot3(&ustr, NULL, NULL)) + goto notfound; + sp += tmplen; + lp += tmplen; + continue; + } + + /* Check if the file exists and use the existing file name */ + goit = FindFirstFileW(tmpshortpath, &wfd); + if (goit == INVALID_HANDLE_VALUE) goto notfound; + FindClose(goit); + strcpyW(tmpshortpath + sp, wfd.cAlternateFileName); + sp += strlenW(tmpshortpath + sp); + lp += tmplen; + } + tmpshortpath[sp] = 0; + + tmplen = strlenW(tmpshortpath) + 1; + if (tmplen <= shortlen) + { + strcpyW(shortpath, tmpshortpath); + TRACE("returning %s\n", debugstr_w(shortpath)); + tmplen--; /* length without 0 */ + } + + return tmplen; + + notfound: + TRACE("not found!\n" ); + SetLastError ( ERROR_FILE_NOT_FOUND ); + return 0; +} + +/*********************************************************************** + * GetShortPathNameA (KERNEL32.@) + */ +DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen ) +{ + UNICODE_STRING longpathW; + WCHAR shortpathW[MAX_PATH]; + DWORD ret, retW; + + if (!longpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + TRACE("%s\n", debugstr_a(longpath)); + + if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + + retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH); + + if (!retW) + ret = 0; + else if (retW > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + ret = 0; + } + else + { + ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL); + if (ret <= shortlen) + { + WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL); + ret--; /* length without 0 */ + } + } + + RtlFreeUnicodeString(&longpathW); + return ret; +} + + diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel38/tests/path.c dlls/kernel/tests/path.c --- dlls/kernel38/tests/path.c 2003-12-06 16:08:32.000000000 +0100 +++ dlls/kernel/tests/path.c 2003-12-13 10:53:55.000000000 +0100 @@ -112,14 +112,11 @@ len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr); ok(len, "GetFullPathNameA failed for: '%s'",subpath); if(HAS_TRAIL_SLASH_A(subpath)) { -/* Wine strips off the trailing '\'. Neither Win98 nor Win2k do this. */ - todo_wine { - ok(strptr==NULL, - "%s: GetFullPathNameA should not return a filename ptr",errstr); - ok(lstrcmpiA(fullpath,tmpstr)==0, - "%s: GetFullPathNameA returned '%s' instead of '%s'", - errstr,tmpstr,fullpath); - } + ok(strptr==NULL, + "%s: GetFullPathNameA should not return a filename ptr %s=>%s",subpath,strptr,errstr); + ok(lstrcmpiA(fullpath,tmpstr)==0, + "%s: GetFullPathNameA returned '%s' instead of '%s'", + errstr,tmpstr,fullpath); } else { ok(lstrcmpiA(strptr,filename)==0, "%s: GetFullPathNameA returned '%s' instead of '%s'", @@ -141,7 +138,7 @@ We test both conversion from GetFullPathNameA and from GetShortPathNameA */ if(pGetLongPathNameA) { - if(len==0) { + if(len!=0) { SetLastError(0); len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH); if(passfail==NULL) { @@ -160,12 +157,9 @@ if(passfail==NULL) { ok(len, "%s: GetLongPathNameA failed",errstr); if(HAS_TRAIL_SLASH_A(fullpath)) { -/* Wine strips off the trailing '\' Neither Win98 nor Win2k do this */ - todo_wine { - ok(lstrcmpiA(fullpathlong,tmpstr)==0, + ok(lstrcmpiA(fullpathlong,tmpstr)==0, "%s: GetLongPathNameA returned '%s' instead of '%s'", errstr,tmpstr,fullpathlong); - } } else { ok(lstrcmpiA(fullpathlong,tmpstr)==0, "%s: GetLongPathNameA returned '%s' instead of '%s'", @@ -229,7 +223,7 @@ /* Test that Get(Short|Long|Full)PathNameA work correctly with interesting characters in the filename. 'valid' indicates whether this would be an allowed filename - 'todo' indictaes that wine doesn't get this right yet. + 'todo' indicates that wine doesn't get this right yet. NOTE: We always call this routine with a non-existent filename, so Get(Short|Long)PathNameA should never pass, but GetFullPathNameA should. @@ -518,13 +512,11 @@ "GetLongPathNameA: wrong return code, %ld instead of %d", rc1, strlen(tmpstr)+1);
- todo_wine { - sprintf(dir,"%c:",curDrive); - rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr)); - ok(strcmp(dir,tmpstr)==0, - "GetLongPathNameA: returned '%s' instead of '%s' (rc=%ld)", - tmpstr,dir,rc1); - } + sprintf(dir,"%c:",curDrive); + rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr)); + ok(strcmp(dir,tmpstr)==0, + "GetLongPathNameA: returned '%s' instead of '%s' (rc=%ld)", + tmpstr,dir,rc1); }
/* Check the cases where both file and directory exist first */ @@ -773,11 +765,9 @@ ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed"); test_SplitShortPathA(tmpstr,dir,eight,three); if(pGetLongPathNameA) { - ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed"); - todo_wine { - ok(lstrcmpiA(tmpstr1,LONGDIR)==0, - "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,LONGDIR); - } + ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed"); + ok(lstrcmpiA(tmpstr1,LONGDIR)==0, + "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,LONGDIR); } sprintf(tmpstr,".\%s",LONGDIR); ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed"); @@ -785,11 +775,10 @@ ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0', "GetShortPathNameA did not keep relative directory [%s]",tmpstr1); if(pGetLongPathNameA) { - ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetShortPathNameA failed"); - todo_wine { - ok(lstrcmpiA(tmpstr1,tmpstr)==0, - "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr); - } + ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s", + tmpstr); + ok(lstrcmpiA(tmpstr1,tmpstr)==0, + "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr); } /* Check out Get*PathNameA on some funny characters */ for(i=0;i<lstrlenA(funny_chars);i++) { diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll38/path.c dlls/ntdll/path.c --- dlls/ntdll38/path.c 2003-12-06 16:08:36.000000000 +0100 +++ dlls/ntdll/path.c 2003-12-13 10:52:49.000000000 +0100 @@ -614,6 +614,7 @@ BOOLEAN WINAPI RtlIsNameLegalDOS8Dot3( const UNICODE_STRING *unicode, OEM_STRING *oem, BOOLEAN *spaces ) { + static const char* illegal = "*?<>|"+=,;[]:/\\345"; int dot = -1; unsigned int i; char buffer[12]; @@ -654,7 +655,7 @@ dot = i; break; default: - /* FIXME: check for invalid chars */ + if (strchr(illegal, oem->Buffer[i])) return FALSE; break; } } diff -u -N -r -x '*~' -x '.#*' -x CVS files38/dos_fs.c files/dos_fs.c --- files38/dos_fs.c 2003-12-07 11:24:07.000000000 +0100 +++ files/dos_fs.c 2003-12-13 10:23:45.000000000 +0100 @@ -1173,527 +1173,6 @@
/*********************************************************************** - * GetShortPathNameW (KERNEL32.@) - * - * NOTES - * observed: - * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 - * longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0 - * - * more observations ( with NT 3.51 (WinDD) ): - * longpath <= 8.3 -> just copy longpath to shortpath - * longpath > 8.3 -> - * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND - * b) file does exist -> set the short filename. - * - trailing slashes are reproduced in the short name, even if the - * file is not a directory - * - the absolute/relative path of the short name is reproduced like found - * in the long name - * - longpath and shortpath may have the same address - * Peter Ganten, 1999 - */ -DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen ) -{ - DOS_FULL_NAME full_name; - WCHAR tmpshortpath[MAX_PATHNAME_LEN]; - const WCHAR *p; - DWORD sp = 0, lp = 0; - int drive; - DWORD tmplen; - UINT flags; - BOOL unixabsolute = *longpath == '/'; - - TRACE("%s\n", debugstr_w(longpath)); - - if (!longpath) { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - if (!longpath[0]) { - SetLastError(ERROR_BAD_PATHNAME); - return 0; - } - - /* check for drive letter */ - if (!unixabsolute && longpath[1] == ':' ) { - tmpshortpath[0] = longpath[0]; - tmpshortpath[1] = ':'; - sp = 2; - } - - if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0; - flags = DRIVE_GetFlags ( drive ); - - if (unixabsolute && drive != DRIVE_GetCurrentDrive()) { - tmpshortpath[0] = drive + 'A'; - tmpshortpath[1] = ':'; - sp = 2; - } - - while ( longpath[lp] ) { - - /* check for path delimiters and reproduce them */ - if ( longpath[lp] == '\' || longpath[lp] == '/' ) { - if (!sp || tmpshortpath[sp-1]!= '\') - { - /* strip double "\" */ - tmpshortpath[sp] = '\'; - sp++; - } - tmpshortpath[sp]=0;/*terminate string*/ - lp++; - continue; - } - - tmplen = 0; - for(p = longpath + lp; *p && *p != '/' && *p != '\'; p++) - tmplen++; - lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1); - - /* Check, if the current element is a valid dos name */ - if ( DOSFS_ValidDOSName ( longpath + lp, !(flags & DRIVE_CASE_SENSITIVE) ) ) { - sp += tmplen; - lp += tmplen; - continue; - } - - /* Check if the file exists and use the existing file name */ - if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) { - strcpyW(tmpshortpath + sp, strrchrW(full_name.short_name, '\') + 1); - sp += strlenW(tmpshortpath + sp); - lp += tmplen; - continue; - } - - TRACE("not found!\n" ); - SetLastError ( ERROR_FILE_NOT_FOUND ); - return 0; - } - tmpshortpath[sp] = 0; - - tmplen = strlenW(tmpshortpath) + 1; - if (tmplen <= shortlen) - { - strcpyW(shortpath, tmpshortpath); - TRACE("returning %s\n", debugstr_w(shortpath)); - tmplen--; /* length without 0 */ - } - - return tmplen; -} - - -/*********************************************************************** - * GetShortPathNameA (KERNEL32.@) - */ -DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen ) -{ - UNICODE_STRING longpathW; - WCHAR shortpathW[MAX_PATH]; - DWORD ret, retW; - - if (!longpath) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - TRACE("%s\n", debugstr_a(longpath)); - - if (!RtlCreateUnicodeStringFromAsciiz(&longpathW, longpath)) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - retW = GetShortPathNameW(longpathW.Buffer, shortpathW, MAX_PATH); - - if (!retW) - ret = 0; - else if (retW > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - ret = 0; - } - else - { - ret = WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, NULL, 0, NULL, NULL); - if (ret <= shortlen) - { - WideCharToMultiByte(CP_ACP, 0, shortpathW, -1, shortpath, shortlen, NULL, NULL); - ret--; /* length without 0 */ - } - } - - RtlFreeUnicodeString(&longpathW); - return ret; -} - - -/*********************************************************************** - * GetLongPathNameW (KERNEL32.@) - * - * NOTES - * observed (Win2000): - * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 - * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 - */ -DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) -{ - DOS_FULL_NAME full_name; - const char *root; - LPWSTR p; - int drive; - DWORD ret, len = 0; - - if (!shortpath) { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - if (!shortpath[0]) { - SetLastError(ERROR_PATH_NOT_FOUND); - return 0; - } - - TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen); - - if(shortpath[0]=='\' && shortpath[1]=='\') - { - ERR("UNC pathname %s\n",debugstr_w(shortpath)); - lstrcpynW( longpath, full_name.short_name, longlen ); - return strlenW(longpath); - } - - if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0; - - root = full_name.long_name; - drive = DRIVE_FindDriveRoot(&root); - - ret = MultiByteToWideChar(CP_UNIXCP, 0, root, -1, NULL, 0); - ret += 3; /* A:\ */ - /* reproduce terminating slash */ - if (ret > 4) /* if not drive root */ - { - len = strlenW(shortpath); - if (shortpath[len - 1] == '\' || shortpath[len - 1] == '/') - len = 1; - } - ret += len; - if (ret <= longlen) - { - longpath[0] = 'A' + drive; - longpath[1] = ':'; - MultiByteToWideChar(CP_UNIXCP, 0, root, -1, longpath + 2, longlen - 2); - for (p = longpath; *p; p++) if (*p == '/') *p = '\'; - if (len) - { - longpath[ret - 2] = '\'; - longpath[ret - 1] = 0; - } - TRACE("returning %s\n", debugstr_w(longpath)); - ret--; /* length without 0 */ - } - return ret; -} - - -/*********************************************************************** - * GetLongPathNameA (KERNEL32.@) - */ -DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen ) -{ - UNICODE_STRING shortpathW; - WCHAR longpathW[MAX_PATH]; - DWORD ret, retW; - - if (!shortpath) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - TRACE("%s\n", debugstr_a(shortpath)); - - if (!RtlCreateUnicodeStringFromAsciiz(&shortpathW, shortpath)) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - retW = GetLongPathNameW(shortpathW.Buffer, longpathW, MAX_PATH); - - if (!retW) - ret = 0; - else if (retW > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - ret = 0; - } - else - { - ret = WideCharToMultiByte(CP_ACP, 0, longpathW, -1, NULL, 0, NULL, NULL); - if (ret <= longlen) - { - WideCharToMultiByte(CP_ACP, 0, longpathW, -1, longpath, longlen, NULL, NULL); - ret--; /* length without 0 */ - } - } - - RtlFreeUnicodeString(&shortpathW); - return ret; -} - - -/*********************************************************************** - * DOSFS_DoGetFullPathName - * - * Implementation of GetFullPathNameA/W. - * - * bon@elektron 000331: - * A test for GetFullPathName with many pathological cases - * now gives identical output for Wine and OSR2 - */ -static DWORD DOSFS_DoGetFullPathName( LPCWSTR name, DWORD len, LPWSTR result ) -{ - DWORD ret; - DOS_FULL_NAME full_name; - LPWSTR p, q; - char *p_l; - const char * root; - WCHAR drivecur[] = {'C',':','.',0}; - WCHAR driveletter=0; - int namelen,drive=0; - static const WCHAR bkslashW[] = {'\',0}; - static const WCHAR dotW[] = {'.',0}; - static const WCHAR updir_slashW[] = {'\','.','.','\',0}; - static const WCHAR curdirW[] = {'\','.','\',0}; - static const WCHAR updirW[] = {'\','.','.',0}; - - if (!name[0]) - { - SetLastError(ERROR_BAD_PATHNAME); - return 0; - } - - TRACE("passed %s\n", debugstr_w(name)); - - if (name[1]==':') - /*drive letter given */ - { - driveletter = name[0]; - } - if ((name[1]==':') && ((name[2]=='\') || (name[2]=='/'))) - /*absolute path given */ - { - strncpyW(full_name.short_name, name, MAX_PATHNAME_LEN); - full_name.short_name[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */ - drive = toupperW(name[0]) - 'A'; - } - else - { - if (driveletter) - drivecur[0]=driveletter; - else if ((name[0]=='\') || (name[0]=='/')) - strcpyW(drivecur, bkslashW); - else - strcpyW(drivecur, dotW); - - if (!DOSFS_GetFullName( drivecur, FALSE, &full_name )) - { - FIXME("internal: error getting drive/path\n"); - return 0; - } - /* find path that drive letter substitutes*/ - drive = toupperW(full_name.short_name[0]) - 'A'; - root= DRIVE_GetRoot(drive); - if (!root) - { - FIXME("internal: error getting DOS Drive Root\n"); - return 0; - } - if (!strcmp(root,"/")) - { - /* we have just the last / and we need it. */ - p_l = full_name.long_name; - } - else - { - p_l = full_name.long_name + strlen(root); - } - /* append long name (= unix name) to drive */ - MultiByteToWideChar(CP_UNIXCP, 0, p_l, -1, full_name.short_name + 2, MAX_PATHNAME_LEN - 3); - /* append name to treat */ - namelen= strlenW(full_name.short_name); - p = (LPWSTR)name; - if (driveletter) - p += 2; /* skip drive name when appending */ - if (namelen + 2 + strlenW(p) > MAX_PATHNAME_LEN) - { - FIXME("internal error: buffer too small\n"); - return 0; - } - full_name.short_name[namelen++] ='\'; - full_name.short_name[namelen] = 0; - strncpyW(full_name.short_name + namelen, p, MAX_PATHNAME_LEN - namelen); - full_name.short_name[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */ - } - /* reverse all slashes */ - for (p=full_name.short_name; - p < full_name.short_name + strlenW(full_name.short_name); - p++) - { - if ( *p == '/' ) - *p = '\'; - } - /* Use memmove, as areas overlap */ - /* Delete .. */ - while ((p = strstrW(full_name.short_name, updir_slashW))) - { - if (p > full_name.short_name+2) - { - *p = 0; - q = strrchrW(full_name.short_name, '\'); - memmove(q+1, p+4, (strlenW(p+4)+1) * sizeof(WCHAR)); - } - else - { - memmove(full_name.short_name+3, p+4, (strlenW(p+4)+1) * sizeof(WCHAR)); - } - } - if ((full_name.short_name[2]=='.')&&(full_name.short_name[3]=='.')) - { - /* This case istn't treated yet : c:..\test */ - memmove(full_name.short_name+2,full_name.short_name+4, - (strlenW(full_name.short_name+4)+1) * sizeof(WCHAR)); - } - /* Delete . */ - while ((p = strstrW(full_name.short_name, curdirW))) - { - *(p+1) = 0; - memmove(p+1, p+3, (strlenW(p+3)+1) * sizeof(WCHAR)); - } - if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING)) - for (p = full_name.short_name; *p; p++) *p = toupperW(*p); - namelen = strlenW(full_name.short_name); - if (!strcmpW(full_name.short_name+namelen-3, updirW)) - { - /* one more strange case: "c:\test\test1.." - return "c:\test" */ - *(full_name.short_name+namelen-3)=0; - q = strrchrW(full_name.short_name, '\'); - *q =0; - } - if (full_name.short_name[namelen-1]=='.') - full_name.short_name[(namelen--)-1] =0; - if (!driveletter) - if (full_name.short_name[namelen-1]=='\') - full_name.short_name[(namelen--)-1] =0; - TRACE("got %s\n", debugstr_w(full_name.short_name)); - - /* If the lpBuffer buffer is too small, the return value is the - size of the buffer, in characters, required to hold the path - plus the terminating \0 (tested against win95osr2, bon 001118) - . */ - ret = strlenW(full_name.short_name); - if (ret >= len ) - { - /* don't touch anything when the buffer is not large enough */ - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return ret+1; - } - if (result) - { - strncpyW( result, full_name.short_name, len ); - result[len - 1] = 0; /* ensure 0 termination */ - } - - TRACE("returning %s\n", debugstr_w(full_name.short_name) ); - return ret; -} - - -/*********************************************************************** - * GetFullPathNameA (KERNEL32.@) - * NOTES - * if the path closed with '', *lastpart is 0 - */ -DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, - LPSTR *lastpart ) -{ - UNICODE_STRING nameW; - WCHAR bufferW[MAX_PATH]; - DWORD ret, retW; - - if (!name) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name)) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - retW = GetFullPathNameW( nameW.Buffer, MAX_PATH, bufferW, NULL); - - if (!retW) - ret = 0; - else if (retW > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - ret = 0; - } - else - { - ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); - if (ret <= len) - { - WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, len, NULL, NULL); - ret--; /* length without 0 */ - - if (lastpart) - { - LPSTR p = buffer + strlen(buffer); - - if (*p != '\') - { - while ((p > buffer + 2) && (*p != '\')) p--; - *lastpart = p + 1; - } - else *lastpart = NULL; - } - } - } - - RtlFreeUnicodeString(&nameW); - return ret; -} - - -/*********************************************************************** - * GetFullPathNameW (KERNEL32.@) - */ -DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, - LPWSTR *lastpart ) -{ - DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer ); - if (ret && (ret<=len) && buffer && lastpart) - { - LPWSTR p = buffer + strlenW(buffer); - if (*p != (WCHAR)'\') - { - while ((p > buffer + 2) && (*p != (WCHAR)'\')) p--; - *lastpart = p + 1; - } - else *lastpart = NULL; - } - return ret; -} - - -/*********************************************************************** * wine_get_unix_file_name (KERNEL32.@) Not a Windows API * * Return the full Unix file name for a given path.
Hmm I don't remember that one, it may have gotten lost in the vacation backlog. Could you please resend?
and by the way, this one got lost too A+
Name: ntkrnl_37 ChangeLog: - got rid of FILE_Dup2 export from kernel32 - move all dos handle related code into dlls/kernel32 License: X11 GenDate: 2003/12/07 10:38:48 UTC ModifiedFiles: dlls/kernel/kernel32.spec dlls/kernel/file.c dlls/kernel/file16.c dlls/winedos/int21.c files/file.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/dlls/kernel/kernel32.spec,v retrieving revision 1.120 diff -u -u -r1.120 kernel32.spec --- dlls/kernel/kernel32.spec 25 Nov 2003 01:51:07 -0000 1.120 +++ dlls/kernel/kernel32.spec 7 Dec 2003 09:31:21 -0000 @@ -1147,7 +1147,6 @@ @ cdecl DOSMEM_GetBlock(long ptr) @ cdecl DOSMEM_Init(long) @ cdecl DOSMEM_ResizeBlock(ptr long long) -@ cdecl FILE_Dup2(long long) @ cdecl LOCAL_Alloc(long long long) @ cdecl LOCAL_Compact(long long long) @ cdecl LOCAL_CountFree(long) Index: dlls/kernel/file.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/dlls/kernel/file.c,v retrieving revision 1.4 diff -u -u -r1.4 file.c --- dlls/kernel/file.c 5 Sep 2003 23:08:37 -0000 1.4 +++ dlls/kernel/file.c 7 Dec 2003 10:38:30 -0000 @@ -222,7 +222,6 @@ return (HFILE)CreateFileA( path, access, sharing, NULL, OPEN_EXISTING, 0, 0 ); }
- /*********************************************************************** * _lread (KERNEL32.@) */ @@ -450,3 +449,110 @@ SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT); return FALSE; } + +HANDLE dos_handles[DOS_TABLE_SIZE]; +/*********************************************************************** + * FILE_InitProcessDosHandles + * + * Allocates the default DOS handles for a process. Called either by + * Win32HandleToDosFileHandle below or by the DOSVM stuff. + */ +static void FILE_InitProcessDosHandles( void ) +{ + static BOOL init_done /* = FALSE */; + HANDLE cp = GetCurrentProcess(); + + if (init_done) return; + init_done = TRUE; + DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0], + 0, TRUE, DUPLICATE_SAME_ACCESS); + DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1], + 0, TRUE, DUPLICATE_SAME_ACCESS); + DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2], + 0, TRUE, DUPLICATE_SAME_ACCESS); + DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3], + 0, TRUE, DUPLICATE_SAME_ACCESS); + DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4], + 0, TRUE, DUPLICATE_SAME_ACCESS); +} + +/*********************************************************************** + * Win32HandleToDosFileHandle (KERNEL32.21) + * + * Allocate a DOS handle for a Win32 handle. The Win32 handle is no + * longer valid after this function (even on failure). + * + * Note: this is not exactly right, since on Win95 the Win32 handles + * are on top of DOS handles and we do it the other way + * around. Should be good enough though. + */ +HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle ) +{ + int i; + + if (!handle || (handle == INVALID_HANDLE_VALUE)) + return HFILE_ERROR; + + FILE_InitProcessDosHandles(); + for (i = 0; i < DOS_TABLE_SIZE; i++) + if (!dos_handles[i]) + { + dos_handles[i] = handle; + TRACE("Got %d for h32 %p\n", i, handle ); + return (HFILE)i; + } + CloseHandle( handle ); + SetLastError( ERROR_TOO_MANY_OPEN_FILES ); + return HFILE_ERROR; +} + + +/*********************************************************************** + * DosFileHandleToWin32Handle (KERNEL32.20) + * + * Return the Win32 handle for a DOS handle. + * + * Note: this is not exactly right, since on Win95 the Win32 handles + * are on top of DOS handles and we do it the other way + * around. Should be good enough though. + */ +HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle ) +{ + HFILE16 hfile = (HFILE16)handle; + if (hfile < 5) FILE_InitProcessDosHandles(); + if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile]) + { + SetLastError( ERROR_INVALID_HANDLE ); + return INVALID_HANDLE_VALUE; + } + return dos_handles[hfile]; +} + + +/*********************************************************************** + * DisposeLZ32Handle (KERNEL32.22) + * + * Note: this is not entirely correct, we should only close the + * 32-bit handle and not the 16-bit one, but we cannot do + * this because of the way our DOS handles are implemented. + * It shouldn't break anything though. + */ +void WINAPI DisposeLZ32Handle( HANDLE handle ) +{ + int i; + + if (!handle || (handle == INVALID_HANDLE_VALUE)) return; + + for (i = 5; i < DOS_TABLE_SIZE; i++) + if (dos_handles[i] == handle) + { + dos_handles[i] = 0; + CloseHandle( handle ); + break; + } +} + + + + + Index: dlls/kernel/file16.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/dlls/kernel/file16.c,v retrieving revision 1.4 diff -u -u -r1.4 file16.c --- dlls/kernel/file16.c 15 Nov 2003 00:13:21 -0000 1.4 +++ dlls/kernel/file16.c 7 Dec 2003 10:31:48 -0000 @@ -62,6 +62,21 @@ return _hwrite( (HFILE)DosFileHandleToWin32Handle(hFile), buffer, count ); }
+/*********************************************************************** + * _lclose (KERNEL.81) + */ +HFILE16 WINAPI _lclose16( HFILE16 hFile ) +{ + if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile]) + { + SetLastError( ERROR_INVALID_HANDLE ); + return HFILE_ERROR16; + } + TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] ); + CloseHandle( dos_handles[hFile] ); + dos_handles[hFile] = 0; + return 0; +}
/*********************************************************************** * _lcreat (KERNEL.83) Index: dlls/winedos/int21.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/dlls/winedos/int21.c,v retrieving revision 1.51 diff -u -u -r1.51 int21.c --- dlls/winedos/int21.c 26 Nov 2003 22:29:30 -0000 1.51 +++ dlls/winedos/int21.c 7 Dec 2003 10:35:38 -0000 @@ -3737,6 +3801,44 @@ SET_SI( context, context->Esi + (int)s - (int)filename ); }
+static BOOL INT21_Dup2(HFILE16 hFile1, HFILE16 hFile2) +{ + HFILE16 res; + HANDLE handle, new_handle; +#define DOS_TABLE_SIZE 256 + DWORD map[DOS_TABLE_SIZE / 32]; + int i; + + handle = DosFileHandleToWin32Handle(hFile1); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + _lclose16(hFile2); + /* now loop to allocate the same one... */ + memset(map, 0, sizeof(map)); + for (i = 0; i < DOS_TABLE_SIZE; i++) + { + if (!DuplicateHandle(GetCurrentProcess(), handle, + GetCurrentProcess(), &new_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + res = HFILE_ERROR16; + break; + } + res = Win32HandleToDosFileHandle(new_handle); + if (res == HFILE_ERROR16 || res == hFile2) break; + map[res / 32] |= 1 << (res % 32); + } + /* clean up the allocated slots */ + for (i = 0; i < DOS_TABLE_SIZE; i++) + { + if (map[i / 32] & (1 << (i % 32))) + _lclose16((HFILE16)i); + } + return res == hFile2; +} + + /*********************************************************************** * DOSVM_Int21Handler * @@ -4517,8 +4619,7 @@ case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */ TRACE( "FORCEDUP - FORCE DUPLICATE FILE HANDLE %d to %d\n", BX_reg(context), CX_reg(context) ); - - if (FILE_Dup2( BX_reg(context), CX_reg(context) ) == HFILE_ERROR16) + if (!INT21_Dup2(BX_reg(context), CX_reg(context))) bSetDOSExtendedError = TRUE; else RESET_CFLAG(context); Index: files/file.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/files/file.c,v retrieving revision 1.195 diff -u -u -r1.195 file.c --- files/file.c 2 Dec 2003 04:48:16 -0000 1.195 +++ files/file.c 7 Dec 2003 10:30:34 -0000 @@ -84,7 +84,6 @@
#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
-HANDLE dos_handles[DOS_TABLE_SIZE]; mode_t FILE_umask;
/*********************************************************************** @@ -1277,146 +1276,6 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode ) { return FILE_DoOpenFile( name, ofs, mode, TRUE ); -} - - -/*********************************************************************** - * FILE_InitProcessDosHandles - * - * Allocates the default DOS handles for a process. Called either by - * Win32HandleToDosFileHandle below or by the DOSVM stuff. - */ -static void FILE_InitProcessDosHandles( void ) -{ - HANDLE cp = GetCurrentProcess(); - DuplicateHandle(cp, GetStdHandle(STD_INPUT_HANDLE), cp, &dos_handles[0], - 0, TRUE, DUPLICATE_SAME_ACCESS); - DuplicateHandle(cp, GetStdHandle(STD_OUTPUT_HANDLE), cp, &dos_handles[1], - 0, TRUE, DUPLICATE_SAME_ACCESS); - DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[2], - 0, TRUE, DUPLICATE_SAME_ACCESS); - DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[3], - 0, TRUE, DUPLICATE_SAME_ACCESS); - DuplicateHandle(cp, GetStdHandle(STD_ERROR_HANDLE), cp, &dos_handles[4], - 0, TRUE, DUPLICATE_SAME_ACCESS); -} - -/*********************************************************************** - * Win32HandleToDosFileHandle (KERNEL32.21) - * - * Allocate a DOS handle for a Win32 handle. The Win32 handle is no - * longer valid after this function (even on failure). - * - * Note: this is not exactly right, since on Win95 the Win32 handles - * are on top of DOS handles and we do it the other way - * around. Should be good enough though. - */ -HFILE WINAPI Win32HandleToDosFileHandle( HANDLE handle ) -{ - int i; - - if (!handle || (handle == INVALID_HANDLE_VALUE)) - return HFILE_ERROR; - - for (i = 5; i < DOS_TABLE_SIZE; i++) - if (!dos_handles[i]) - { - dos_handles[i] = handle; - TRACE("Got %d for h32 %p\n", i, handle ); - return (HFILE)i; - } - CloseHandle( handle ); - SetLastError( ERROR_TOO_MANY_OPEN_FILES ); - return HFILE_ERROR; -} - - -/*********************************************************************** - * DosFileHandleToWin32Handle (KERNEL32.20) - * - * Return the Win32 handle for a DOS handle. - * - * Note: this is not exactly right, since on Win95 the Win32 handles - * are on top of DOS handles and we do it the other way - * around. Should be good enough though. - */ -HANDLE WINAPI DosFileHandleToWin32Handle( HFILE handle ) -{ - HFILE16 hfile = (HFILE16)handle; - if (hfile < 5 && !dos_handles[hfile]) FILE_InitProcessDosHandles(); - if ((hfile >= DOS_TABLE_SIZE) || !dos_handles[hfile]) - { - SetLastError( ERROR_INVALID_HANDLE ); - return INVALID_HANDLE_VALUE; - } - return dos_handles[hfile]; -} - - -/*********************************************************************** - * DisposeLZ32Handle (KERNEL32.22) - * - * Note: this is not entirely correct, we should only close the - * 32-bit handle and not the 16-bit one, but we cannot do - * this because of the way our DOS handles are implemented. - * It shouldn't break anything though. - */ -void WINAPI DisposeLZ32Handle( HANDLE handle ) -{ - int i; - - if (!handle || (handle == INVALID_HANDLE_VALUE)) return; - - for (i = 5; i < DOS_TABLE_SIZE; i++) - if (dos_handles[i] == handle) - { - dos_handles[i] = 0; - CloseHandle( handle ); - break; - } -} - - -/*********************************************************************** - * FILE_Dup2 - * - * dup2() function for DOS handles. - */ -HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 ) -{ - HANDLE new_handle; - - if (hFile1 < 5 && !dos_handles[hFile1]) FILE_InitProcessDosHandles(); - - if ((hFile1 >= DOS_TABLE_SIZE) || (hFile2 >= DOS_TABLE_SIZE) || !dos_handles[hFile1]) - { - SetLastError( ERROR_INVALID_HANDLE ); - return HFILE_ERROR16; - } - if (!DuplicateHandle( GetCurrentProcess(), dos_handles[hFile1], - GetCurrentProcess(), &new_handle, - 0, FALSE, DUPLICATE_SAME_ACCESS )) - return HFILE_ERROR16; - if (dos_handles[hFile2]) CloseHandle( dos_handles[hFile2] ); - dos_handles[hFile2] = new_handle; - return hFile2; -} - - -/*********************************************************************** - * _lclose (KERNEL.81) - */ -HFILE16 WINAPI _lclose16( HFILE16 hFile ) -{ - if ((hFile >= DOS_TABLE_SIZE) || !dos_handles[hFile]) - { - SetLastError( ERROR_INVALID_HANDLE ); - return HFILE_ERROR16; - } - TRACE("%d (handle32=%p)\n", hFile, dos_handles[hFile] ); - CloseHandle( dos_handles[hFile] ); - dos_handles[hFile] = 0; - return 0; }