diff --git a/dlls/kernel/wowthunk.c b/dlls/kernel/wowthunk.c index 6c1926e8c09..c223880bd96 100644 --- a/dlls/kernel/wowthunk.c +++ b/dlls/kernel/wowthunk.c @@ -20,7 +20,9 @@ #include "wine/winbase16.h" #include "winbase.h" +#include "winerror.h" #include "wownt32.h" +#include "ntddk.h" #include "file.h" #include "miscemu.h" #include "stackframe.h" @@ -319,17 +321,35 @@ DWORD WINAPI LoadLibraryEx32W16( LPCSTR lpszLibFile, DWORD hFile, DWORD dwFlags HMODULE hModule; DOS_FULL_NAME full_name; DWORD mutex_count; + UNICODE_STRING libfileW; + LPCWSTR filenameW; + static const WCHAR dllW[] = {'.','D','L','L',0}; + + if (!lpszLibFile) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (!RtlCreateUnicodeStringFromAsciiz(&libfileW, lpszLibFile)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } /* if the file can not be found, call LoadLibraryExA anyway, since it might be a buildin module. This case is handled in MODULE_LoadLibraryExA */ - if ( ! DIR_SearchPath ( NULL, lpszLibFile, ".DLL", &full_name, FALSE ) ) { - strcpy ( full_name.short_name, lpszLibFile ); - } + filenameW = libfileW.Buffer; + if ( DIR_SearchPath( NULL, filenameW, dllW, &full_name, FALSE ) ) + filenameW = full_name.short_name; ReleaseThunkLock( &mutex_count ); - hModule = LoadLibraryExA( full_name.short_name, (HANDLE)hFile, dwFlags ); + hModule = LoadLibraryExW( filenameW, (HANDLE)hFile, dwFlags ); RestoreThunkLock( mutex_count ); + + RtlFreeUnicodeString(&libfileW); + return (DWORD)hModule; } diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 1439715fb79..6159d41db43 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -29,6 +29,7 @@ #ifdef HAVE_SYS_ERRNO_H #include #endif +#include "wine/unicode.h" #include "wine/debug.h" #include "wine/server.h" #include "ntdll_misc.h" @@ -60,9 +61,8 @@ NTSTATUS WINAPI NtOpenFile( ULONG ShareAccess, ULONG OpenOptions) { - ULONG len = 0; - PSTR filename; - CHAR szDosDevices[] = "\\DosDevices\\"; + LPWSTR filename; + static const WCHAR szDosDevices[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0}; DOS_FULL_NAME full_name; NTSTATUS r; @@ -79,20 +79,14 @@ NTSTATUS WINAPI NtOpenFile( return STATUS_OBJECT_NAME_NOT_FOUND; } - /* create an ascii string from the unicode filename */ - RtlUnicodeToMultiByteSize( &len, ObjectAttributes->ObjectName->Buffer, - ObjectAttributes->ObjectName->Length ); - filename = RtlAllocateHeap( GetProcessHeap(), 0, len + 1); - RtlUnicodeToMultiByteN(filename, len, NULL, ObjectAttributes->ObjectName->Buffer, - ObjectAttributes->ObjectName->Length ); - filename[len]=0; + filename = ObjectAttributes->ObjectName->Buffer; /* FIXME: DOSFS stuff should call here, not vice-versa */ - if(strncmp(filename, szDosDevices, strlen(szDosDevices))) + if(strncmpW(filename, szDosDevices, strlenW(szDosDevices))) return STATUS_OBJECT_NAME_NOT_FOUND; /* FIXME: this calls SetLastError() -> bad */ - if(!DOSFS_GetFullName(&filename[strlen(szDosDevices)], TRUE, + if(!DOSFS_GetFullName(&filename[strlenW(szDosDevices)], TRUE, &full_name)) return STATUS_OBJECT_NAME_NOT_FOUND; @@ -105,7 +99,7 @@ NTSTATUS WINAPI NtOpenFile( req->sharing = ShareAccess; req->create = OPEN_EXISTING; req->attrs = 0; - req->drive_type = GetDriveTypeA( full_name.short_name ); + req->drive_type = GetDriveTypeW( full_name.short_name ); wine_server_add_data( req, full_name.long_name, strlen(full_name.long_name) ); SetLastError(0); r = wine_server_call( req ); diff --git a/dlls/winedos/int21.c b/dlls/winedos/int21.c index 7f21dca995a..d652b6af06d 100644 --- a/dlls/winedos/int21.c +++ b/dlls/winedos/int21.c @@ -32,16 +32,18 @@ #include "miscemu.h" #include "msdos.h" #include "file.h" +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(int21); void WINAPI DOSVM_Int21Handler_Ioctl( CONTEXT86 *context ) { + static const WCHAR emmxxxx0W[] = {'E','M','M','X','X','X','X','0',0}; const DOS_DEVICE *dev = DOSFS_GetDeviceByHandle( DosFileHandleToWin32Handle(BX_reg(context)) ); - if (dev && !strcasecmp( dev->name, "EMMXXXX0" )) { + if (dev && !strcmpiW( dev->name, emmxxxx0W )) { EMS_Ioctl_Handler(context); return; } diff --git a/files/directory.c b/files/directory.c index 9e3f3cd2cb1..8dfae7e4da9 100644 --- a/files/directory.c +++ b/files/directory.c @@ -41,6 +41,8 @@ #include "wine/winuser16.h" #include "winerror.h" #include "winreg.h" +#include "ntddk.h" +#include "wine/unicode.h" #include "drive.h" #include "file.h" #include "heap.h" @@ -53,27 +55,30 @@ WINE_DECLARE_DEBUG_CHANNEL(file); static DOS_FULL_NAME DIR_Windows; static DOS_FULL_NAME DIR_System; +static const WCHAR wineW[] = {'w','i','n','e',0}; /*********************************************************************** * DIR_GetPath * * Get a path name from the wine.ini file and make sure it is valid. */ -static int DIR_GetPath( const char *keyname, const char *defval, - DOS_FULL_NAME *full_name, char * longname, BOOL warn ) +static int DIR_GetPath( LPCWSTR keyname, LPCWSTR defval, DOS_FULL_NAME *full_name, + LPWSTR longname, INT longname_len, BOOL warn ) { - char path[MAX_PATHNAME_LEN]; + WCHAR path[MAX_PATHNAME_LEN]; BY_HANDLE_FILE_INFORMATION info; const char *mess = "does not exist"; - PROFILE_GetWineIniString( "wine", keyname, defval, path, sizeof(path) ); + PROFILE_GetWineIniString( wineW, keyname, defval, path, MAX_PATHNAME_LEN ); + if (!DOSFS_GetFullName( path, TRUE, full_name ) || (!FILE_Stat( full_name->long_name, &info ) && (mess=strerror(errno)))|| (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (mess="not a directory")) || - (!(GetLongPathNameA(full_name->short_name, longname, MAX_PATHNAME_LEN))) ) + (!(GetLongPathNameW(full_name->short_name, longname, longname_len))) ) { if (warn) - MESSAGE("Invalid path '%s' for %s directory: %s\n", path, keyname, mess); + MESSAGE("Invalid path %s for %s directory: %s\n", + debugstr_w(path), debugstr_w(keyname), mess); return 0; } return 1; @@ -86,10 +91,27 @@ static int DIR_GetPath( const char *keyname, const char *defval, int DIR_Init(void) { char path[MAX_PATHNAME_LEN]; - char longpath[MAX_PATHNAME_LEN]; + WCHAR longpath[MAX_PATHNAME_LEN]; DOS_FULL_NAME tmp_dir, profile_dir; int drive; const char *cwd; + static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0}; + static const WCHAR systemW[] = {'s','y','s','t','e','m',0}; + static const WCHAR tempW[] = {'t','e','m','p',0}; + static const WCHAR profileW[] = {'p','r','o','f','i','l','e',0}; + static const WCHAR windows_dirW[] = {'c',':','\\','w','i','n','d','o','w','s',0}; + static const WCHAR system_dirW[] = {'c',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m',0}; + static const WCHAR pathW[] = {'p','a','t','h',0}; + static const WCHAR path_dirW[] = {'c',':','\\','w','i','n','d','o','w','s',';', + 'c',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m',0}; + static const WCHAR path_capsW[] = {'P','A','T','H',0}; + static const WCHAR temp_capsW[] = {'T','E','M','P',0}; + static const WCHAR tmp_capsW[] = {'T','M','P',0}; + static const WCHAR windirW[] = {'w','i','n','d','i','r',0}; + static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0}; + static const WCHAR userprofileW[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; + static const WCHAR systemrootW[] = {'S','Y','S','T','E','M','R','O','O','T',0}; + static const WCHAR empty_strW[] = { 0 }; if (!getcwd( path, MAX_PATHNAME_LEN )) { @@ -105,13 +127,17 @@ int DIR_Init(void) } else { + WCHAR szdrive[3]={drive+'A',':',0}; + MultiByteToWideChar(DRIVE_GetCodepage(drive), 0, cwd, -1, longpath, MAX_PATHNAME_LEN); DRIVE_SetCurrentDrive( drive ); - DRIVE_Chdir( drive, cwd ); + DRIVE_Chdir( drive, longpath ); + if(GetDriveTypeW(szdrive)==DRIVE_CDROM) + chdir("/"); /* change to root directory so as not to lock cdroms */ } - if (!(DIR_GetPath( "windows", "c:\\windows", &DIR_Windows, longpath, TRUE )) || - !(DIR_GetPath( "system", "c:\\windows\\system", &DIR_System, longpath, TRUE )) || - !(DIR_GetPath( "temp", "c:\\windows", &tmp_dir, longpath, TRUE ))) + if (!(DIR_GetPath( windowsW, windows_dirW, &DIR_Windows, longpath, MAX_PATHNAME_LEN, TRUE )) || + !(DIR_GetPath( systemW, system_dirW, &DIR_System, longpath, MAX_PATHNAME_LEN, TRUE )) || + !(DIR_GetPath( tempW, windows_dirW, &tmp_dir, longpath, MAX_PATHNAME_LEN, TRUE ))) { PROFILE_UsageWineIni(); return 0; @@ -135,9 +161,8 @@ int DIR_Init(void) DRIVE_Chdir( drive, DIR_Windows.short_name + 2 ); } - PROFILE_GetWineIniString("wine", "path", "c:\\windows;c:\\windows\\system", - path, sizeof(path) ); - if (strchr(path, '/')) + PROFILE_GetWineIniString(wineW, pathW, path_dirW, longpath, MAX_PATHNAME_LEN); + if (strchrW(longpath, '/')) { MESSAGE("Fix your wine config to use DOS drive syntax in [wine] 'Path=' statement! (no '/' allowed)\n"); PROFILE_UsageWineIni(); @@ -146,34 +171,34 @@ int DIR_Init(void) /* Set the environment variables */ - SetEnvironmentVariableA( "PATH", path ); - SetEnvironmentVariableA( "TEMP", tmp_dir.short_name ); - SetEnvironmentVariableA( "TMP", tmp_dir.short_name ); - SetEnvironmentVariableA( "windir", DIR_Windows.short_name ); - SetEnvironmentVariableA( "winsysdir", DIR_System.short_name ); + SetEnvironmentVariableW( path_capsW, longpath ); + SetEnvironmentVariableW( temp_capsW, tmp_dir.short_name ); + SetEnvironmentVariableW( tmp_capsW, tmp_dir.short_name ); + SetEnvironmentVariableW( windirW, DIR_Windows.short_name ); + SetEnvironmentVariableW( winsysdirW, DIR_System.short_name ); /* set COMSPEC only if it doesn't exist already */ if (!GetEnvironmentVariableA( "COMSPEC", NULL, 0 )) SetEnvironmentVariableA( "COMSPEC", "c:\\command.com" ); TRACE("WindowsDir = %s (%s)\n", - DIR_Windows.short_name, DIR_Windows.long_name ); + debugstr_w(DIR_Windows.short_name), DIR_Windows.long_name ); TRACE("SystemDir = %s (%s)\n", - DIR_System.short_name, DIR_System.long_name ); + debugstr_w(DIR_System.short_name), DIR_System.long_name ); TRACE("TempDir = %s (%s)\n", - tmp_dir.short_name, tmp_dir.long_name ); - TRACE("Path = %s\n", path ); + debugstr_w(tmp_dir.short_name), tmp_dir.long_name ); + TRACE("Path = %s\n", debugstr_w(longpath) ); TRACE("Cwd = %c:\\%s\n", - 'A' + drive, DRIVE_GetDosCwd( drive ) ); + 'A' + drive, debugstr_w(DRIVE_GetDosCwd(drive)) ); - if (DIR_GetPath( "profile", "", &profile_dir, longpath, FALSE )) + if (DIR_GetPath( profileW, empty_strW, &profile_dir, longpath, MAX_PATHNAME_LEN, FALSE )) { - TRACE("USERPROFILE= %s\n", longpath ); - SetEnvironmentVariableA( "USERPROFILE", longpath ); + TRACE("USERPROFILE= %s\n", debugstr_w(longpath) ); + SetEnvironmentVariableW( userprofileW, longpath ); } - TRACE("SYSTEMROOT = %s\n", DIR_Windows.short_name ); - SetEnvironmentVariableA( "SYSTEMROOT", DIR_Windows.short_name ); + TRACE("SYSTEMROOT = %s\n", debugstr_w(DIR_Windows.short_name) ); + SetEnvironmentVariableW( systemrootW, DIR_Windows.short_name ); return 1; } @@ -184,15 +209,25 @@ int DIR_Init(void) */ UINT WINAPI GetTempPathA( UINT count, LPSTR path ) { + WCHAR pathW[MAX_PATH]; UINT ret; - if (!(ret = GetEnvironmentVariableA( "TMP", path, count ))) - if (!(ret = GetEnvironmentVariableA( "TEMP", path, count ))) - if (!(ret = GetCurrentDirectoryA( count, path ))) - return 0; - if (count && (ret < count - 1) && (path[ret-1] != '\\')) + + ret = GetTempPathW(MAX_PATH, pathW); + + if (!ret) + return 0; + + if (ret > MAX_PATH) { - path[ret++] = '\\'; - path[ret] = '\0'; + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return 0; + } + + ret = WideCharToMultiByte(CP_ACP, 0, pathW, -1, NULL, 0, NULL, NULL); + if (ret <= count) + { + WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, count, NULL, NULL); + ret--; /* length without 0 */ } return ret; } @@ -205,16 +240,49 @@ UINT WINAPI GetTempPathW( UINT count, LPWSTR path ) { static const WCHAR tmp[] = { 'T', 'M', 'P', 0 }; static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 }; + WCHAR tmp_path[MAX_PATH]; UINT ret; - if (!(ret = GetEnvironmentVariableW( tmp, path, count ))) - if (!(ret = GetEnvironmentVariableW( temp, path, count ))) - if (!(ret = GetCurrentDirectoryW( count, path ))) + + TRACE("%u,%p\n", count, path); + + if (!(ret = GetEnvironmentVariableW( tmp, tmp_path, MAX_PATH ))) + if (!(ret = GetEnvironmentVariableW( temp, tmp_path, MAX_PATH ))) + if (!(ret = GetCurrentDirectoryW( MAX_PATH, tmp_path ))) return 0; - if (count && (ret < count - 1) && (path[ret-1] != '\\')) + + if (ret > MAX_PATH) { - path[ret++] = '\\'; - path[ret] = '\0'; + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return 0; } + + ret = GetFullPathNameW(tmp_path, MAX_PATH, tmp_path, NULL); + if (!ret) return 0; + + if (ret > MAX_PATH - 2) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return 0; + } + + if (tmp_path[ret-1] != '\\') + { + tmp_path[ret++] = '\\'; + tmp_path[ret] = '\0'; + } + + ret++; /* add space for terminating 0 */ + + if (count) + { + lstrcpynW(path, tmp_path, count); + if (count >= ret) + ret--; /* return length without 0 */ + else if (count < 4) + path[0] = 0; /* avoid returning ambiguous "X:" */ + } + + TRACE("returning %u, %s\n", ret, debugstr_w(path)); return ret; } @@ -278,16 +346,16 @@ UINT16 WINAPI GetWindowsDirectory16( LPSTR path, UINT16 count ) /*********************************************************************** - * GetWindowsDirectoryA (KERNEL32.@) + * GetWindowsDirectoryW (KERNEL32.@) * - * See comment for GetWindowsDirectoryW. + * See comment for GetWindowsDirectoryA. */ -UINT WINAPI GetWindowsDirectoryA( LPSTR path, UINT count ) +UINT WINAPI GetWindowsDirectoryW( LPWSTR path, UINT count ) { - UINT len = strlen( DIR_Windows.short_name ) + 1; + UINT len = strlenW( DIR_Windows.short_name ) + 1; if (path && count >= len) { - strcpy( path, DIR_Windows.short_name ); + strcpyW( path, DIR_Windows.short_name ); len--; } return len; @@ -295,7 +363,7 @@ UINT WINAPI GetWindowsDirectoryA( LPSTR path, UINT count ) /*********************************************************************** - * GetWindowsDirectoryW (KERNEL32.@) + * GetWindowsDirectoryA (KERNEL32.@) * * Return value: * If buffer is large enough to hold full path and terminating '\0' character @@ -303,12 +371,12 @@ UINT WINAPI GetWindowsDirectoryA( LPSTR path, UINT count ) * Otherwise function returns required size including '\0' character and * does not touch the buffer. */ -UINT WINAPI GetWindowsDirectoryW( LPWSTR path, UINT count ) +UINT WINAPI GetWindowsDirectoryA( LPSTR path, UINT count ) { - UINT len = MultiByteToWideChar( CP_ACP, 0, DIR_Windows.short_name, -1, NULL, 0 ); + UINT len = WideCharToMultiByte( CP_ACP, 0, DIR_Windows.short_name, -1, NULL, 0, NULL, NULL ); if (path && count >= len) { - MultiByteToWideChar( CP_ACP, 0, DIR_Windows.short_name, -1, path, count ); + WideCharToMultiByte( CP_ACP, 0, DIR_Windows.short_name, -1, path, count, NULL, NULL ); len--; } return len; @@ -343,16 +411,16 @@ UINT16 WINAPI GetSystemDirectory16( LPSTR path, UINT16 count ) /*********************************************************************** - * GetSystemDirectoryA (KERNEL32.@) + * GetSystemDirectoryW (KERNEL32.@) * - * See comment for GetWindowsDirectoryW. + * See comment for GetWindowsDirectoryA. */ -UINT WINAPI GetSystemDirectoryA( LPSTR path, UINT count ) +UINT WINAPI GetSystemDirectoryW( LPWSTR path, UINT count ) { - UINT len = strlen( DIR_System.short_name ) + 1; + UINT len = strlenW( DIR_System.short_name ) + 1; if (path && count >= len) { - strcpy( path, DIR_System.short_name ); + strcpyW( path, DIR_System.short_name ); len--; } return len; @@ -360,16 +428,16 @@ UINT WINAPI GetSystemDirectoryA( LPSTR path, UINT count ) /*********************************************************************** - * GetSystemDirectoryW (KERNEL32.@) + * GetSystemDirectoryA (KERNEL32.@) * - * See comment for GetWindowsDirectoryW. + * See comment for GetWindowsDirectoryA. */ -UINT WINAPI GetSystemDirectoryW( LPWSTR path, UINT count ) +UINT WINAPI GetSystemDirectoryA( LPSTR path, UINT count ) { - UINT len = MultiByteToWideChar( CP_ACP, 0, DIR_System.short_name, -1, NULL, 0 ); + UINT len = WideCharToMultiByte( CP_ACP, 0, DIR_System.short_name, -1, NULL, 0, NULL, NULL ); if (path && count >= len) { - MultiByteToWideChar( CP_ACP, 0, DIR_System.short_name, -1, path, count ); + WideCharToMultiByte( CP_ACP, 0, DIR_System.short_name, -1, path, count, NULL, NULL ); len--; } return len; @@ -387,7 +455,7 @@ BOOL16 WINAPI CreateDirectory16( LPCSTR path, LPVOID dummy ) /*********************************************************************** - * CreateDirectoryA (KERNEL32.@) + * CreateDirectoryW (KERNEL32.@) * RETURNS: * TRUE : success * FALSE : failure @@ -396,15 +464,22 @@ BOOL16 WINAPI CreateDirectory16( LPCSTR path, LPVOID dummy ) * ERROR_ACCESS_DENIED: on permission problems * ERROR_FILENAME_EXCED_RANGE: too long filename(s) */ -BOOL WINAPI CreateDirectoryA( LPCSTR path, +BOOL WINAPI CreateDirectoryW( LPCWSTR path, LPSECURITY_ATTRIBUTES lpsecattribs ) { DOS_FULL_NAME full_name; - TRACE_(file)("(%s,%p)\n", path, lpsecattribs ); + if (!path || !*path) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return FALSE; + } + + TRACE_(file)("(%s,%p)\n", debugstr_w(path), lpsecattribs ); + if (DOSFS_GetDevice( path )) { - TRACE_(file)("cannot use device '%s'!\n",path); + TRACE_(file)("cannot use device %s!\n", debugstr_w(path)); SetLastError( ERROR_ACCESS_DENIED ); return FALSE; } @@ -414,7 +489,14 @@ BOOL WINAPI CreateDirectoryA( LPCSTR path, /* the FILE_SetDosError() generated error codes don't match the * CreateDirectory ones for some errnos */ switch (errno) { - case EEXIST: SetLastError(ERROR_ALREADY_EXISTS); break; + case EEXIST: + { + if (!strcmp(DRIVE_GetRoot(full_name.drive), full_name.long_name)) + SetLastError(ERROR_ACCESS_DENIED); + else + SetLastError(ERROR_ALREADY_EXISTS); + break; + } case ENOSPC: SetLastError(ERROR_DISK_FULL); break; default: FILE_SetDosError();break; } @@ -425,14 +507,27 @@ BOOL WINAPI CreateDirectoryA( LPCSTR path, /*********************************************************************** - * CreateDirectoryW (KERNEL32.@) + * CreateDirectoryA (KERNEL32.@) */ -BOOL WINAPI CreateDirectoryW( LPCWSTR path, +BOOL WINAPI CreateDirectoryA( LPCSTR path, LPSECURITY_ATTRIBUTES lpsecattribs ) { - LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path ); - BOOL ret = CreateDirectoryA( xpath, lpsecattribs ); - HeapFree( GetProcessHeap(), 0, xpath ); + UNICODE_STRING pathW; + BOOL ret = FALSE; + + if (!path || !*path) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&pathW, path)) + { + ret = CreateDirectoryW(pathW.Buffer, lpsecattribs); + RtlFreeUnicodeString(&pathW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); return ret; } @@ -467,17 +562,23 @@ BOOL16 WINAPI RemoveDirectory16( LPCSTR path ) /*********************************************************************** - * RemoveDirectoryA (KERNEL32.@) + * RemoveDirectoryW (KERNEL32.@) */ -BOOL WINAPI RemoveDirectoryA( LPCSTR path ) +BOOL WINAPI RemoveDirectoryW( LPCWSTR path ) { DOS_FULL_NAME full_name; - TRACE_(file)("'%s'\n", path ); + if (!path) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + TRACE_(file)("%s\n", debugstr_w(path)); if (DOSFS_GetDevice( path )) { - TRACE_(file)("cannot remove device '%s'!\n", path); + TRACE_(file)("cannot remove device %s!\n", debugstr_w(path)); SetLastError( ERROR_FILE_NOT_FOUND ); return FALSE; } @@ -492,13 +593,26 @@ BOOL WINAPI RemoveDirectoryA( LPCSTR path ) /*********************************************************************** - * RemoveDirectoryW (KERNEL32.@) + * RemoveDirectoryA (KERNEL32.@) */ -BOOL WINAPI RemoveDirectoryW( LPCWSTR path ) +BOOL WINAPI RemoveDirectoryA( LPCSTR path ) { - LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path ); - BOOL ret = RemoveDirectoryA( xpath ); - HeapFree( GetProcessHeap(), 0, xpath ); + UNICODE_STRING pathW; + BOOL ret = FALSE; + + if (!path) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&pathW, path)) + { + ret = RemoveDirectoryW(pathW.Buffer); + RtlFreeUnicodeString(&pathW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); return ret; } @@ -508,53 +622,58 @@ BOOL WINAPI RemoveDirectoryW( LPCWSTR path ) * * Helper function for DIR_SearchPath. */ -static BOOL DIR_TryPath( const DOS_FULL_NAME *dir, LPCSTR name, +static BOOL DIR_TryPath( const DOS_FULL_NAME *dir, LPCWSTR name, DOS_FULL_NAME *full_name ) { LPSTR p_l = full_name->long_name + strlen(dir->long_name) + 1; - LPSTR p_s = full_name->short_name + strlen(dir->short_name) + 1; + LPWSTR p_s = full_name->short_name + strlenW(dir->short_name) + 1; - if ((p_s >= full_name->short_name + sizeof(full_name->short_name) - 14) || + if ((p_s >= full_name->short_name + sizeof(full_name->short_name)/sizeof(full_name->short_name[0]) - 14) || (p_l >= full_name->long_name + sizeof(full_name->long_name) - 1)) { SetLastError( ERROR_PATH_NOT_FOUND ); return FALSE; } - if (!DOSFS_FindUnixName( dir->long_name, name, p_l, + if (!DOSFS_FindUnixName( dir, name, p_l, sizeof(full_name->long_name) - (p_l - full_name->long_name), p_s, !(DRIVE_GetFlags(dir->drive) & DRIVE_CASE_SENSITIVE) )) return FALSE; + + full_name->drive = dir->drive; strcpy( full_name->long_name, dir->long_name ); p_l[-1] = '/'; - strcpy( full_name->short_name, dir->short_name ); + strcpyW( full_name->short_name, dir->short_name ); p_s[-1] = '\\'; return TRUE; } -static BOOL DIR_SearchSemicolonedPaths(LPCSTR name, DOS_FULL_NAME *full_name, LPSTR pathlist) +static BOOL DIR_SearchSemicolonedPaths(LPCWSTR name, DOS_FULL_NAME *full_name, LPWSTR pathlist) { - LPSTR next, buffer = NULL; - INT len = strlen(name), newlen, currlen = 0; + LPWSTR next, buffer = NULL; + INT len = strlenW(name), newlen, currlen = 0; BOOL ret = FALSE; next = pathlist; while (!ret && next) { - LPSTR cur = next; + static const WCHAR bkslashW[] = {'\\',0}; + LPWSTR cur = next; while (*cur == ';') cur++; if (!*cur) break; - next = strchr( cur, ';' ); + next = strchrW( cur, ';' ); if (next) *next++ = '\0'; - newlen = strlen(cur) + len + 2; + newlen = strlenW(cur) + len + 2; + if (newlen > currlen) { - if (!(buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, newlen))) + if (!(buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, newlen * sizeof(WCHAR)))) goto done; currlen = newlen; } - strcpy( buffer, cur ); - strcat( buffer, "\\" ); - strcat( buffer, name ); + + strcpyW( buffer, cur ); + strcatW( buffer, bkslashW ); + strcatW( buffer, name ); ret = DOSFS_GetFullName( buffer, TRUE, full_name ); } done: @@ -569,17 +688,18 @@ done: * Helper function for DIR_SearchPath. * Search in the specified path, or in $PATH if NULL. */ -static BOOL DIR_TryEnvironmentPath( LPCSTR name, DOS_FULL_NAME *full_name, LPCSTR envpath ) +static BOOL DIR_TryEnvironmentPath( LPCWSTR name, DOS_FULL_NAME *full_name, LPCWSTR envpath ) { - LPSTR path; + LPWSTR path; BOOL ret = FALSE; DWORD size; + static const WCHAR pathW[] = {'P','A','T','H',0}; - size = envpath ? strlen(envpath)+1 : GetEnvironmentVariableA( "PATH", NULL, 0 ); + size = envpath ? strlenW(envpath)+1 : GetEnvironmentVariableW( pathW, NULL, 0 ); if (!size) return FALSE; - if (!(path = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; - if (envpath) strcpy( path, envpath ); - else if (!GetEnvironmentVariableA( "PATH", path, size )) goto done; + if (!(path = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; + if (envpath) strcpyW( path, envpath ); + else if (!GetEnvironmentVariableW( pathW, path, size )) goto done; ret = DIR_SearchSemicolonedPaths(name, full_name, path); @@ -594,27 +714,28 @@ done: * * Helper function for DIR_SearchPath. */ -static BOOL DIR_TryModulePath( LPCSTR name, DOS_FULL_NAME *full_name, BOOL win32 ) +static BOOL DIR_TryModulePath( LPCWSTR name, DOS_FULL_NAME *full_name, BOOL win32 ) { - /* FIXME: for now, GetModuleFileNameA can't return more */ + /* FIXME: for now, GetModuleFileNameW can't return more */ /* than OFS_MAXPATHNAME. This may change with Win32. */ - - char buffer[OFS_MAXPATHNAME]; - LPSTR p; + WCHAR bufferW[OFS_MAXPATHNAME]; + LPWSTR p; if (!win32) { + char buffer[OFS_MAXPATHNAME]; if (!GetCurrentTask()) return FALSE; if (!GetModuleFileName16( GetCurrentTask(), buffer, sizeof(buffer) )) - buffer[0]='\0'; + return FALSE; + MultiByteToWideChar(CP_ACP, 0, buffer, -1, bufferW, OFS_MAXPATHNAME); } else { - if (!GetModuleFileNameA( 0, buffer, sizeof(buffer) )) - buffer[0]='\0'; + if (!GetModuleFileNameW( 0, bufferW, OFS_MAXPATHNAME ) ) + return FALSE; } - if (!(p = strrchr( buffer, '\\' ))) return FALSE; - if (sizeof(buffer) - (++p - buffer) <= strlen(name)) return FALSE; - strcpy( p, name ); - return DOSFS_GetFullName( buffer, TRUE, full_name ); + if (!(p = strrchrW( bufferW, '\\' ))) return FALSE; + if (OFS_MAXPATHNAME - (++p - bufferW) <= strlenW(name)) return FALSE; + strcpyW( p, name ); + return DOSFS_GetFullName( bufferW, TRUE, full_name ); } @@ -623,32 +744,33 @@ static BOOL DIR_TryModulePath( LPCSTR name, DOS_FULL_NAME *full_name, BOOL win32 * * Helper function for DIR_SearchPath. */ -static BOOL DIR_TryAppPath( LPCSTR name, DOS_FULL_NAME *full_name ) +static BOOL DIR_TryAppPath( LPCWSTR name, DOS_FULL_NAME *full_name ) { HKEY hkAppPaths = 0, hkApp = 0; - char lpAppName[MAX_PATHNAME_LEN], lpAppPaths[MAX_PATHNAME_LEN]; - LPSTR lpFileName; + WCHAR lpAppName[MAX_PATHNAME_LEN], lpAppPaths[MAX_PATHNAME_LEN]; + LPWSTR lpFileName; BOOL res = FALSE; DWORD type, count; + static const WCHAR PathW[] = {'P','a','t','h',0}; if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths", &hkAppPaths) != ERROR_SUCCESS) return FALSE; - if (GetModuleFileNameA(0, lpAppName, sizeof(lpAppName)) == 0) + if (!GetModuleFileNameW(0, lpAppName, MAX_PATHNAME_LEN)) { WARN("huh, module not found ??\n"); goto end; } - lpFileName = strrchr(lpAppName, '\\'); + lpFileName = strrchrW(lpAppName, '\\'); if (!lpFileName) goto end; else lpFileName++; /* skip '\\' */ - if (RegOpenKeyA(hkAppPaths, lpFileName, &hkApp) != ERROR_SUCCESS) + if (RegOpenKeyW(hkAppPaths, lpFileName, &hkApp) != ERROR_SUCCESS) goto end; count = sizeof(lpAppPaths); - if (RegQueryValueExA(hkApp, "Path", 0, &type, (LPBYTE)lpAppPaths, &count) != ERROR_SUCCESS) + if (RegQueryValueExW(hkApp, PathW, 0, &type, (LPBYTE)lpAppPaths, &count) != ERROR_SUCCESS) goto end; - TRACE("successfully opened App Paths for '%s'\n", lpFileName); + TRACE("successfully opened App Paths for %s\n", debugstr_w(lpFileName)); res = DIR_SearchSemicolonedPaths(name, full_name, lpAppPaths); end: @@ -667,19 +789,19 @@ end: * * FIXME: should return long path names. */ -DWORD DIR_SearchPath( LPCSTR path, LPCSTR name, LPCSTR ext, +DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DOS_FULL_NAME *full_name, BOOL win32 ) { - LPCSTR p; - LPSTR tmp = NULL; + LPCWSTR p; + LPWSTR tmp = NULL; BOOL ret = TRUE; /* First check the supplied parameters */ - p = strrchr( name, '.' ); - if (p && !strchr( p, '/' ) && !strchr( p, '\\' )) + p = strrchrW( name, '.' ); + if (p && !strchrW( p, '/' ) && !strchrW( p, '\\' )) ext = NULL; /* Ignore the specified extension */ - if (FILE_contains_path (name)) + if (FILE_contains_pathW (name)) path = NULL; /* Ignore path if name already contains a path */ if (path && !*path) path = NULL; /* Ignore empty path */ @@ -687,20 +809,20 @@ DWORD DIR_SearchPath( LPCSTR path, LPCSTR name, LPCSTR ext, if (ext) { - DWORD len = strlen(name) + strlen(ext); - if (!(tmp = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) + DWORD len = strlenW(name) + strlenW(ext); + if (!(tmp = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) { SetLastError( ERROR_OUTOFMEMORY ); return 0; } - strcpy( tmp, name ); - strcat( tmp, ext ); + strcpyW( tmp, name ); + strcatW( tmp, ext ); name = tmp; } /* If the name contains an explicit path, everything's easy */ - if (FILE_contains_path(name)) + if (FILE_contains_pathW(name)) { ret = DOSFS_GetFullName( name, TRUE, full_name ); goto done; @@ -751,7 +873,7 @@ done: /*********************************************************************** - * SearchPathA [KERNEL32.@] + * SearchPathW [KERNEL32.@] * * Searches for a specified file in the search path. * @@ -778,10 +900,10 @@ done: * If the file is not found, calls SetLastError(ERROR_FILE_NOT_FOUND) * (tested on NT 4.0) */ -DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, DWORD buflen, - LPSTR buffer, LPSTR *lastpart ) +DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen, + LPWSTR buffer, LPWSTR *lastpart ) { - LPSTR p, res; + LPSTR res; DOS_FULL_NAME full_name; if (!DIR_SearchPath( path, name, ext, &full_name, TRUE )) @@ -789,60 +911,72 @@ DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, DWORD buflen, SetLastError(ERROR_FILE_NOT_FOUND); return 0; } - lstrcpynA( buffer, full_name.short_name, buflen ); + +TRACE("found %s %s\n", full_name.long_name, debugstr_w(full_name.short_name)); +TRACE("drive %c: root %s\n", 'A' + full_name.drive, DRIVE_GetRoot(full_name.drive)); + + lstrcpynW( buffer, full_name.short_name, buflen ); res = full_name.long_name + - strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' )); + strlen(DRIVE_GetRoot( full_name.drive )); while (*res == '/') res++; if (buflen) { - if (buflen > 3) lstrcpynA( buffer + 3, res, buflen - 3 ); + LPWSTR p; + if (buflen > 3) + { + MultiByteToWideChar(DRIVE_GetCodepage(full_name.drive), 0, + res, -1, buffer + 3, buflen - 3); + buffer[buflen - 1] = 0; + } for (p = buffer; *p; p++) if (*p == '/') *p = '\\'; - if (lastpart) *lastpart = strrchr( buffer, '\\' ) + 1; + if (lastpart) *lastpart = strrchrW( buffer, '\\' ) + 1; } - TRACE("Returning %d\n", strlen(res) + 3 ); - return strlen(res) + 3; + TRACE("Returning %s\n", debugstr_w(buffer) ); + return strlenW(buffer); } /*********************************************************************** - * SearchPathW (KERNEL32.@) + * SearchPathA (KERNEL32.@) */ -DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, - DWORD buflen, LPWSTR buffer, LPWSTR *lastpart ) +DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, + DWORD buflen, LPSTR buffer, LPSTR *lastpart ) { - LPWSTR p; - LPSTR res; - DOS_FULL_NAME full_name; + UNICODE_STRING pathW, nameW, extW; + WCHAR bufferW[MAX_PATH]; + DWORD ret, retW; - LPSTR pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, path ); - LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); - LPSTR extA = HEAP_strdupWtoA( GetProcessHeap(), 0, ext ); - DWORD ret = DIR_SearchPath( pathA, nameA, extA, &full_name, TRUE ); - HeapFree( GetProcessHeap(), 0, extA ); - HeapFree( GetProcessHeap(), 0, nameA ); - HeapFree( GetProcessHeap(), 0, pathA ); - if (!ret) return 0; + if (path) RtlCreateUnicodeStringFromAsciiz(&pathW, path); + else pathW.Buffer = NULL; + if (name) RtlCreateUnicodeStringFromAsciiz(&nameW, name); + else nameW.Buffer = NULL; + if (ext) RtlCreateUnicodeStringFromAsciiz(&extW, ext); + else extW.Buffer = NULL; - if (buflen > 0 && !MultiByteToWideChar( CP_ACP, 0, full_name.short_name, -1, buffer, buflen )) - buffer[buflen-1] = 0; - res = full_name.long_name + - strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' )); - while (*res == '/') res++; - if (buflen) + retW = SearchPathW(pathW.Buffer, nameW.Buffer, extW.Buffer, MAX_PATH, bufferW, NULL); + + if (!retW) + ret = 0; + else if (retW > MAX_PATH) { - if (buflen > 3) + SetLastError(ERROR_FILENAME_EXCED_RANGE); + ret = 0; + } + else + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL); + if (buflen >= ret) { - if (!MultiByteToWideChar( CP_ACP, 0, res, -1, buffer+3, buflen-3 )) - buffer[buflen-1] = 0; - } - for (p = buffer; *p; p++) if (*p == '/') *p = '\\'; - if (lastpart) - { - for (p = *lastpart = buffer; *p; p++) - if (*p == '\\') *lastpart = p + 1; + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buflen, NULL, NULL); + ret--; /* length without 0 */ + if (lastpart) *lastpart = strrchr(buffer, '\\') + 1; } } - return strlen(res) + 3; + + RtlFreeUnicodeString(&pathW); + RtlFreeUnicodeString(&nameW); + RtlFreeUnicodeString(&extW); + return ret; } @@ -852,31 +986,31 @@ DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, * * FIXME: should return long path names.? */ -static BOOL search_alternate_path(LPCSTR dll_path, LPCSTR name, LPCSTR ext, +static BOOL search_alternate_path(LPCWSTR dll_path, LPCWSTR name, LPCWSTR ext, DOS_FULL_NAME *full_name) { - LPCSTR p; - LPSTR tmp = NULL; + LPCWSTR p; + LPWSTR tmp = NULL; BOOL ret = TRUE; /* First check the supplied parameters */ - p = strrchr( name, '.' ); - if (p && !strchr( p, '/' ) && !strchr( p, '\\' )) + p = strrchrW( name, '.' ); + if (p && !strchrW( p, '/' ) && !strchrW( p, '\\' )) ext = NULL; /* Ignore the specified extension */ /* Allocate a buffer for the file name and extension */ if (ext) { - DWORD len = strlen(name) + strlen(ext); - if (!(tmp = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) + DWORD len = strlenW(name) + strlenW(ext); + if (!(tmp = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) { SetLastError( ERROR_OUTOFMEMORY ); return 0; } - strcpy( tmp, name ); - strcat( tmp, ext ); + strcpyW( tmp, name ); + strcatW( tmp, ext ); name = tmp; } @@ -922,28 +1056,42 @@ static BOOL search_alternate_path(LPCSTR dll_path, LPCSTR name, LPCSTR ext, * * NOTES * If the file is not found, calls SetLastError(ERROR_FILE_NOT_FOUND) + * + * FIXME: convert to unicode */ DWORD DIR_SearchAlternatePath( LPCSTR dll_path, LPCSTR name, LPCSTR ext, DWORD buflen, LPSTR buffer, LPSTR *lastpart ) { - LPSTR p, res; + LPSTR p; DOS_FULL_NAME full_name; + DWORD ret = 0; + UNICODE_STRING dll_pathW, nameW, extW; - if (!search_alternate_path( dll_path, name, ext, &full_name)) + if (dll_path) RtlCreateUnicodeStringFromAsciiz(&dll_pathW, dll_path); + else dll_pathW.Buffer = NULL; + if (name) RtlCreateUnicodeStringFromAsciiz(&nameW, name); + else nameW.Buffer = NULL; + if (ext) RtlCreateUnicodeStringFromAsciiz(&extW, ext); + else extW.Buffer = NULL; + + if (search_alternate_path( dll_pathW.Buffer, nameW.Buffer, extW.Buffer, &full_name)) { - SetLastError(ERROR_FILE_NOT_FOUND); - return 0; + ret = WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1, NULL, 0, NULL, NULL); + if (buflen >= ret) + { + WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1, buffer, buflen, NULL, NULL); + for (p = buffer; *p; p++) if (*p == '/') *p = '\\'; + if (lastpart) *lastpart = strrchr( buffer, '\\' ) + 1; + ret--; /* length without 0 */ + } } - lstrcpynA( buffer, full_name.short_name, buflen ); - res = full_name.long_name + - strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' )); - while (*res == '/') res++; - if (buflen) - { - if (buflen > 3) lstrcpynA( buffer + 3, res, buflen - 3 ); - for (p = buffer; *p; p++) if (*p == '/') *p = '\\'; - if (lastpart) *lastpart = strrchr( buffer, '\\' ) + 1; - } - TRACE("Returning %d\n", strlen(res) + 3 ); - return strlen(res) + 3; + else + SetLastError(ERROR_FILE_NOT_FOUND); + + RtlFreeUnicodeString(&dll_pathW); + RtlFreeUnicodeString(&nameW); + RtlFreeUnicodeString(&extW); + + TRACE("Returning %ld\n", ret ); + return ret; } diff --git a/files/dos_fs.c b/files/dos_fs.c index 3b0abea2709..f7e58063f72 100644 --- a/files/dos_fs.c +++ b/files/dos_fs.c @@ -85,43 +85,40 @@ typedef struct static const DOS_DEVICE DOSFS_Devices[] = /* name, device flags (see Int 21/AX=0x4400) */ { - { "CON", 0xc0d3 }, - { "PRN", 0xa0c0 }, - { "NUL", 0x80c4 }, - { "AUX", 0x80c0 }, - { "LPT1", 0xa0c0 }, - { "LPT2", 0xa0c0 }, - { "LPT3", 0xa0c0 }, - { "LPT4", 0xc0d3 }, - { "COM1", 0x80c0 }, - { "COM2", 0x80c0 }, - { "COM3", 0x80c0 }, - { "COM4", 0x80c0 }, - { "SCSIMGR$", 0xc0c0 }, - { "HPSCAN", 0xc0c0 }, - { "EMMXXXX0", 0x0000 } + { {'C','O','N',0}, 0xc0d3 }, + { {'P','R','N',0}, 0xa0c0 }, + { {'N','U','L',0}, 0x80c4 }, + { {'A','U','X',0}, 0x80c0 }, + { {'L','P','T','1',0}, 0xa0c0 }, + { {'L','P','T','2',0}, 0xa0c0 }, + { {'L','P','T','3',0}, 0xa0c0 }, + { {'L','P','T','4',0}, 0xc0d3 }, + { {'C','O','M','1',0}, 0x80c0 }, + { {'C','O','M','2',0}, 0x80c0 }, + { {'C','O','M','3',0}, 0x80c0 }, + { {'C','O','M','4',0}, 0x80c0 }, + { {'S','C','S','I','M','G','R','$',0}, 0xc0c0 }, + { {'H','P','S','C','A','N',0}, 0xc0c0 }, + { {'E','M','M','X','X','X','X','0',0}, 0x0000 } }; -#define GET_DRIVE(path) \ - (((path)[1] == ':') ? FILE_toupper((path)[0]) - 'A' : DOSFS_CurDrive) - -/* Directory info for DOSFS_ReadDir */ +/* + * Directory info for DOSFS_ReadDir + * contains the names of *all* the files in the directory + */ typedef struct { - DIR *dir; -#ifdef VFAT_IOCTL_READDIR_BOTH - int fd; - char short_name[12]; - KERNEL_DIRENT dirent[2]; -#endif + int used; + int size; + char names[1]; } DOS_DIR; /* Info structure for FindFirstFile handle */ typedef struct { - LPSTR path; - LPSTR long_mask; - LPSTR short_mask; + char *path; /* unix path */ + LPWSTR long_mask; + LPWSTR short_mask; BYTE attr; int drive; int cur_pos; @@ -148,10 +145,10 @@ static WINE_EXCEPTION_FILTER(page_fault) * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format). * File name can be terminated by '\0', '\\' or '/'. */ -static int DOSFS_ValidDOSName( const char *name, int ignore_case ) +static int DOSFS_ValidDOSName( LPCWSTR name, int ignore_case ) { static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS; - const char *p = name; + const WCHAR *p = name; const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars; int len = 0; @@ -165,7 +162,7 @@ static int DOSFS_ValidDOSName( const char *name, int ignore_case ) } while (!IS_END_OF_NAME(*p)) { - if (strchr( invalid, *p )) return 0; /* Invalid char */ + if (*p < 256 && strchr( invalid, (char)*p )) return 0; /* Invalid char */ if (*p == '.') break; /* Start of the extension */ if (++len > 8) return 0; /* Name too long */ p++; @@ -176,7 +173,7 @@ static int DOSFS_ValidDOSName( const char *name, int ignore_case ) len = 0; while (!IS_END_OF_NAME(*p)) { - if (strchr( invalid, *p )) return 0; /* Invalid char */ + if (*p < 256 && strchr( invalid, (char)*p )) return 0; /* Invalid char */ if (*p == '.') return 0; /* Second extension not allowed */ if (++len > 3) return 0; /* Extension too long */ p++; @@ -194,17 +191,19 @@ static int DOSFS_ValidDOSName( const char *name, int ignore_case ) * Return FALSE if the name is not a valid DOS name. * 'buffer' must be at least 12 characters long. */ -BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ) +BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer ) { static const char invalid_chars[] = INVALID_DOS_CHARS; - const char *p = name; + LPCWSTR p = name; int i; /* Check for "." and ".." */ if (*p == '.') { p++; - strcpy( buffer, ". " ); + buffer[0] = '.'; + for(i = 1; i < 11; i++) buffer[i] = ' '; + buffer[11] = 0; if (*p == '.') { buffer[1] = '.'; @@ -230,8 +229,8 @@ BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ) buffer[i] = '?'; break; default: - if (strchr( invalid_chars, *p )) return FALSE; - buffer[i] = FILE_toupper(*p); + if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE; + buffer[i] = toupperW(*p); p++; break; } @@ -267,8 +266,8 @@ BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ) buffer[i] = '?'; break; default: - if (strchr( invalid_chars, *p )) return FALSE; - buffer[i] = FILE_toupper(*p); + if (*p < 256 && strchr( invalid_chars, (char)*p )) return FALSE; + buffer[i] = toupperW(*p); p++; break; } @@ -291,15 +290,15 @@ BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ) * File name can be terminated by '\0', '\\' or '/'. * 'buffer' must be at least 13 characters long. */ -static void DOSFS_ToDosDTAFormat( LPCSTR name, LPSTR buffer ) +static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer ) { - char *p; + LPWSTR p; - memcpy( buffer, name, 8 ); + memcpy( buffer, name, 8 * sizeof(WCHAR) ); p = buffer + 8; while ((p > buffer) && (p[-1] == ' ')) p--; *p++ = '.'; - memcpy( p, name + 8, 3 ); + memcpy( p, name + 8, 3 * sizeof(WCHAR) ); p += 3; while (p[-1] == ' ') p--; if (p[-1] == '.') p--; @@ -312,7 +311,7 @@ static void DOSFS_ToDosDTAFormat( LPCSTR name, LPSTR buffer ) * * Check a DOS file name against a mask (both in FCB format). */ -static int DOSFS_MatchShort( const char *mask, const char *name ) +static int DOSFS_MatchShort( LPCWSTR mask, LPCWSTR name ) { int i; for (i = 11; i > 0; i--, mask++, name++) @@ -337,13 +336,13 @@ static int DOSFS_MatchShort( const char *mask, const char *name ) * *test1.txt* test1.txt * * h?l?o*t.dat hellothisisatest.dat * */ -static int DOSFS_MatchLong( const char *mask, const char *name, - int case_sensitive ) +static int DOSFS_MatchLong( LPCWSTR mask, LPCWSTR name, int case_sensitive ) { - const char *lastjoker = NULL; - const char *next_to_retry = NULL; + LPCWSTR lastjoker = NULL; + LPCWSTR next_to_retry = NULL; + static const WCHAR asterisk_dot_asterisk[] = {'*','.','*',0}; - if (!strcmp( mask, "*.*" )) return 1; + if (!strcmpW( mask, asterisk_dot_asterisk )) return 1; while (*name && *mask) { if (*mask == '*') @@ -355,7 +354,7 @@ static int DOSFS_MatchLong( const char *mask, const char *name, /* skip to the next match after the joker(s) */ if (case_sensitive) while (*name && (*name != *mask)) name++; - else while (*name && (FILE_toupper(*name) != FILE_toupper(*mask))) name++; + else while (*name && (toupperW(*name) != toupperW(*mask))) name++; if (!*name) break; next_to_retry = name; @@ -369,7 +368,7 @@ static int DOSFS_MatchLong( const char *mask, const char *name, } else { - if (FILE_toupper(*mask) != FILE_toupper(*name)) mismatch = 1; + if (toupperW(*mask) != toupperW(*name)) mismatch = 1; } if (!mismatch) { @@ -410,50 +409,162 @@ static int DOSFS_MatchLong( const char *mask, const char *name, } +/*********************************************************************** + * DOSFS_AddDirEntry + * + * Used to construct an array of filenames in DOSFS_OpenDir + */ +static BOOL DOSFS_AddDirEntry(DOS_DIR **dir, LPCWSTR name, LPCWSTR dosname) +{ + int extra1 = (strlenW(name) + 1) * sizeof(WCHAR); + int extra2 = (strlenW(dosname) + 1) * sizeof(WCHAR); + + /* if we need more, at minimum double the size */ + if( (extra1 + extra2 + (*dir)->used) > (*dir)->size) + { + int more = (*dir)->size; + DOS_DIR *t; + + if(more<(extra1+extra2)) + more = extra1+extra2; + + t = HeapReAlloc(GetProcessHeap(), 0, *dir, sizeof(**dir) + (*dir)->size + more ); + if(!t) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + ERR("Out of memory caching directory structure %d %d %d\n", + (*dir)->size, more, (*dir)->used); + return FALSE; + } + (*dir) = t; + (*dir)->size += more; + } + + /* at this point, the dir structure is big enough to hold these names */ + strcpyW((LPWSTR)&(*dir)->names[(*dir)->used], name); + (*dir)->used += extra1; + strcpyW((LPWSTR)&(*dir)->names[(*dir)->used], dosname); + (*dir)->used += extra2; + + return TRUE; +} + + +/*********************************************************************** + * DOSFS_OpenDir_VFAT + */ +static BOOL DOSFS_OpenDir_VFAT(UINT codepage, DOS_DIR **dir, const char *unix_path) +{ +#ifdef VFAT_IOCTL_READDIR_BOTH + KERNEL_DIRENT de[2]; + int fd = open( unix_path, O_RDONLY ); + BOOL r = TRUE; + + /* Check if the VFAT ioctl is supported on this directory */ + + if ( fd<0 ) + return FALSE; + + while (1) + { + WCHAR long_name[MAX_PATH]; + WCHAR short_name[12]; + + r = (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) != -1); + if(!r) + break; + if (!de[0].d_reclen) + break; + MultiByteToWideChar(codepage, 0, de[0].d_name, -1, long_name, MAX_PATH); + if (!DOSFS_ToDosFCBFormat( long_name, short_name )) + short_name[0] = '\0'; + if (de[1].d_name[0]) + MultiByteToWideChar(codepage, 0, de[1].d_name, -1, long_name, MAX_PATH); + else + MultiByteToWideChar(codepage, 0, de[0].d_name, -1, long_name, MAX_PATH); + r = DOSFS_AddDirEntry(dir, long_name, short_name ); + if(!r) + break; + } + if(r) + { + static const WCHAR empty_strW[] = { 0 }; + DOSFS_AddDirEntry(dir, empty_strW, empty_strW); + } + close(fd); + return r; +#else + return FALSE; +#endif /* VFAT_IOCTL_READDIR_BOTH */ +} + + +/*********************************************************************** + * DOSFS_OpenDir_Normal + * + * Now use the standard opendir/readdir interface + */ +static BOOL DOSFS_OpenDir_Normal( UINT codepage, DOS_DIR **dir, const char *unix_path ) +{ + DIR *unixdir = opendir( unix_path ); + BOOL r = TRUE; + static const WCHAR empty_strW[] = { 0 }; + + if(!unixdir) + return FALSE; + while(1) + { + WCHAR long_name[MAX_PATH]; + struct dirent *de = readdir(unixdir); + + if(!de) + break; + MultiByteToWideChar(codepage, 0, de->d_name, -1, long_name, MAX_PATH); + r = DOSFS_AddDirEntry(dir, long_name, empty_strW); + if(!r) + break; + } + if(r) + DOSFS_AddDirEntry(dir, empty_strW, empty_strW); + closedir(unixdir); + return r; +} + /*********************************************************************** * DOSFS_OpenDir */ -static DOS_DIR *DOSFS_OpenDir( LPCSTR path ) +static DOS_DIR *DOSFS_OpenDir( UINT codepage, const char *unix_path ) { - DOS_DIR *dir = HeapAlloc( GetProcessHeap(), 0, sizeof(*dir) ); + const int init_size = 0x100; + DOS_DIR *dir = HeapAlloc( GetProcessHeap(), 0, sizeof(*dir) + init_size); + BOOL r; + + TRACE("%s\n",debugstr_a(unix_path)); + if (!dir) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return NULL; } + dir->used = 0; + dir->size = init_size; /* Treat empty path as root directory. This simplifies path split into directory and mask in several other places */ - if (!*path) path = "/"; + if (!*unix_path) unix_path = "/"; -#ifdef VFAT_IOCTL_READDIR_BOTH + r = DOSFS_OpenDir_VFAT( codepage, &dir, unix_path); - /* Check if the VFAT ioctl is supported on this directory */ + if(!r) + r = DOSFS_OpenDir_Normal( codepage, &dir, unix_path); - if ((dir->fd = open( path, O_RDONLY )) != -1) + if(!r) { - if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) == -1) - { - close( dir->fd ); - dir->fd = -1; - } - else - { - /* Set the file pointer back at the start of the directory */ - lseek( dir->fd, 0, SEEK_SET ); - dir->dir = NULL; - return dir; - } - } -#endif /* VFAT_IOCTL_READDIR_BOTH */ - - /* Now use the standard opendir/readdir interface */ - - if (!(dir->dir = opendir( path ))) - { - HeapFree( GetProcessHeap(), 0, dir ); + HeapFree(GetProcessHeap(), 0, dir); return NULL; } + dir->used = 0; + return dir; } @@ -463,10 +574,6 @@ static DOS_DIR *DOSFS_OpenDir( LPCSTR path ) */ static void DOSFS_CloseDir( DOS_DIR *dir ) { -#ifdef VFAT_IOCTL_READDIR_BOTH - if (dir->fd != -1) close( dir->fd ); -#endif /* VFAT_IOCTL_READDIR_BOTH */ - if (dir->dir) closedir( dir->dir ); HeapFree( GetProcessHeap(), 0, dir ); } @@ -474,29 +581,30 @@ static void DOSFS_CloseDir( DOS_DIR *dir ) /*********************************************************************** * DOSFS_ReadDir */ -static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCSTR *long_name, - LPCSTR *short_name ) +static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCWSTR *long_name, + LPCWSTR *short_name ) { - struct dirent *dirent; + LPCWSTR sn, ln; -#ifdef VFAT_IOCTL_READDIR_BOTH - if (dir->fd != -1) - { - if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) != -1) { - if (!dir->dirent[0].d_reclen) return FALSE; - if (!DOSFS_ToDosFCBFormat( dir->dirent[0].d_name, dir->short_name )) - dir->short_name[0] = '\0'; - *short_name = dir->short_name; - if (dir->dirent[1].d_name[0]) *long_name = dir->dirent[1].d_name; - else *long_name = dir->dirent[0].d_name; - return TRUE; - } - } -#endif /* VFAT_IOCTL_READDIR_BOTH */ + if (!dir) + return FALSE; + + /* the long pathname is first */ + ln = (LPCWSTR)&dir->names[dir->used]; + if(ln[0]) + *long_name = ln; + else + return FALSE; + dir->used += (strlenW(ln) + 1) * sizeof(WCHAR); + + /* followed by the short path name */ + sn = (LPCWSTR)&dir->names[dir->used]; + if(sn[0]) + *short_name = sn; + else + *short_name = NULL; + dir->used += (strlenW(sn) + 1) * sizeof(WCHAR); - if (!(dirent = readdir( dir->dir ))) return FALSE; - *long_name = dirent->d_name; - *short_name = NULL; return TRUE; } @@ -510,18 +618,22 @@ static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCSTR *long_name, * File name can be terminated by '\0', '\\' or '/'. * 'buffer' must be at least 13 characters long. */ -static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, +static void DOSFS_Hash( LPCWSTR name, LPWSTR buffer, BOOL dir_format, BOOL ignore_case ) { static const char invalid_chars[] = INVALID_DOS_CHARS "~."; static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; - const char *p, *ext; - char *dst; + LPCWSTR p, ext; + LPWSTR dst; unsigned short hash; int i; - if (dir_format) strcpy( buffer, " " ); + if (dir_format) + { + for(i = 0; i < 11; i++) buffer[i] = ' '; + buffer[11] = 0; + } if (DOSFS_ValidDOSName( name, ignore_case )) { @@ -537,13 +649,13 @@ static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, /* Simply copy the name, converting to uppercase */ for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++) - *dst++ = FILE_toupper(*name); + *dst++ = toupperW(*name); if (*name == '.') { if (dir_format) dst = buffer + 8; else *dst++ = '.'; for (name++; !IS_END_OF_NAME(*name); name++) - *dst++ = FILE_toupper(*name); + *dst++ = toupperW(*name); } if (!dir_format) *dst = '\0'; return; @@ -555,8 +667,8 @@ static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, if (ignore_case) { for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++) - hash = (hash<<3) ^ (hash>>5) ^ FILE_tolower(*p) ^ (FILE_tolower(p[1]) << 8); - hash = (hash<<3) ^ (hash>>5) ^ FILE_tolower(*p); /* Last character*/ + hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p) ^ (tolowerW(p[1]) << 8); + hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p); /* Last character */ } else { @@ -575,7 +687,7 @@ static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, for (i = 4, p = name, dst = buffer; i > 0; i--, p++) { if (IS_END_OF_NAME(*p) || (p == ext)) break; - *dst++ = strchr( invalid_chars, *p ) ? '_' : FILE_toupper(*p); + *dst++ = (*p < 256 && strchr( invalid_chars, (char)*p )) ? '_' : toupperW(*p); } /* Pad to 5 chars with '~' */ while (i-- >= 0) *dst++ = '~'; @@ -590,7 +702,7 @@ static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, { if (!dir_format) *dst++ = '.'; for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++) - *dst++ = strchr( invalid_chars, *ext ) ? '_' : FILE_toupper(*ext); + *dst++ = (*ext < 256 && strchr( invalid_chars, (char)*ext )) ? '_' : toupperW(*ext); } if (!dir_format) *dst = '\0'; } @@ -608,44 +720,44 @@ static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, * turns out to be larger than that, the function returns FALSE. * 'short_buf' must be at least 13 characters long. */ -BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, - INT long_len, LPSTR short_buf, BOOL ignore_case) +BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf, + INT long_len, LPWSTR short_buf, BOOL ignore_case) { DOS_DIR *dir; - LPCSTR long_name, short_name; - char dos_name[12], tmp_buf[13]; + LPCWSTR long_name, short_name; + WCHAR dos_name[12], tmp_buf[13]; BOOL ret; - const char *p = strchr( name, '/' ); - int len = p ? (int)(p - name) : strlen(name); - if ((p = strchr( name, '\\' ))) len = min( (int)(p - name), len ); + LPCWSTR p = strchrW( name, '/' ); + int len = p ? (int)(p - name) : strlenW(name); + if ((p = strchrW( name, '\\' ))) len = min( (int)(p - name), len ); /* Ignore trailing dots and spaces */ while (len > 1 && (name[len-1] == '.' || name[len-1] == ' ')) len--; if (long_len < len + 1) return FALSE; - TRACE("%s,%s\n", path, name ); + TRACE("%s,%s\n", path->long_name, debugstr_w(name) ); if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0'; - if (!(dir = DOSFS_OpenDir( path ))) + if (!(dir = DOSFS_OpenDir( DRIVE_GetCodepage(path->drive), path->long_name ))) { WARN("(%s,%s): can't open dir: %s\n", - path, name, strerror(errno) ); + path->long_name, debugstr_w(name), strerror(errno) ); return FALSE; } while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name ))) { /* Check against Unix name */ - if (len == strlen(long_name)) + if (len == strlenW(long_name)) { if (!ignore_case) { - if (!strncmp( long_name, name, len )) break; + if (!strncmpW( long_name, name, len )) break; } else { - if (!FILE_strncasecmp( long_name, name, len )) break; + if (!strncmpiW( long_name, name, len )) break; } } if (dos_name[0]) @@ -656,12 +768,13 @@ BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case ); short_name = tmp_buf; } - if (!strcmp( dos_name, short_name )) break; + if (!strcmpW( dos_name, short_name )) break; } } if (ret) { - if (long_buf) strcpy( long_buf, long_name ); + if (long_buf) WideCharToMultiByte(DRIVE_GetCodepage(path->drive), 0, + long_name, -1, long_buf, long_len, NULL, NULL); if (short_buf) { if (short_name) @@ -669,11 +782,11 @@ BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, else DOSFS_Hash( long_name, short_buf, FALSE, ignore_case ); } - TRACE("(%s,%s) -> %s (%s)\n", - path, name, long_name, short_buf ? short_buf : "***"); + TRACE("(%s,%s) -> %s (%s)\n", path->long_name, debugstr_w(name), + debugstr_w(long_name), short_buf ? debugstr_w(short_buf) : "***"); } else - WARN("'%s' not found in '%s'\n", name, path); + WARN("%s not found in '%s'\n", debugstr_w(name), path->long_name); DOSFS_CloseDir( dir ); return ret; } @@ -684,21 +797,21 @@ BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, * * Check if a DOS file name represents a DOS device and return the device. */ -const DOS_DEVICE *DOSFS_GetDevice( const char *name ) +const DOS_DEVICE *DOSFS_GetDevice( LPCWSTR name ) { unsigned int i; - const char *p; + const WCHAR *p; if (!name) return NULL; /* if FILE_DupUnixHandle was used */ if (name[0] && (name[1] == ':')) name += 2; - if ((p = strrchr( name, '/' ))) name = p + 1; - if ((p = strrchr( name, '\\' ))) name = p + 1; + if ((p = strrchrW( name, '/' ))) name = p + 1; + if ((p = strrchrW( name, '\\' ))) name = p + 1; for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) { - const char *dev = DOSFS_Devices[i].name; - if (!FILE_strncasecmp( dev, name, strlen(dev) )) + const WCHAR *dev = DOSFS_Devices[i].name; + if (!strncmpiW( dev, name, strlenW(dev) )) { - p = name + strlen( dev ); + p = name + strlenW( dev ); if (!*p || (*p == '.') || (*p == ':')) return &DOSFS_Devices[i]; } } @@ -730,18 +843,23 @@ const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile ) /************************************************************************** * DOSFS_CreateCommPort */ -static HANDLE DOSFS_CreateCommPort(LPCSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa) +static HANDLE DOSFS_CreateCommPort(LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa) { HANDLE ret; char devname[40]; + WCHAR devnameW[40]; + static const WCHAR serialportsW[] = {'s','e','r','i','a','l','p','o','r','t','s',0}; + static const WCHAR empty_strW[] = { 0 }; - TRACE_(file)("%s %lx %lx\n", name, access, attributes); + TRACE_(file)("%s %lx %lx\n", debugstr_w(name), access, attributes); - PROFILE_GetWineIniString("serialports",name,"",devname,sizeof devname); - if(!devname[0]) + PROFILE_GetWineIniString(serialportsW, name, empty_strW, devnameW, 40); + if(!devnameW[0]) return 0; - TRACE("opening %s as %s\n", devname, name); + WideCharToMultiByte(CP_ACP, 0, devnameW, -1, devname, sizeof(devname), NULL, NULL); + + TRACE("opening %s as %s\n", devname, debugstr_w(name)); SERVER_START_REQ( create_serial ) { @@ -769,28 +887,33 @@ static HANDLE DOSFS_CreateCommPort(LPCSTR name, DWORD access, DWORD attributes, * Open a DOS device. This might not map 1:1 into the UNIX device concept. * Returns 0 on failure. */ -HANDLE DOSFS_OpenDevice( const char *name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) +HANDLE DOSFS_OpenDevice( LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) { unsigned int i; - const char *p; + const WCHAR *p; HANDLE handle; if (name[0] && (name[1] == ':')) name += 2; - if ((p = strrchr( name, '/' ))) name = p + 1; - if ((p = strrchr( name, '\\' ))) name = p + 1; + if ((p = strrchrW( name, '/' ))) name = p + 1; + if ((p = strrchrW( name, '\\' ))) name = p + 1; for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) { - const char *dev = DOSFS_Devices[i].name; - if (!FILE_strncasecmp( dev, name, strlen(dev) )) + const WCHAR *dev = DOSFS_Devices[i].name; + if (!strncmpiW( dev, name, strlenW(dev) )) { - p = name + strlen( dev ); + p = name + strlenW( dev ); if (!*p || (*p == '.') || (*p == ':')) { + static const WCHAR nulW[] = {'N','U','L',0}; + static const WCHAR conW[] = {'C','O','N',0}; + static const WCHAR scsimgrW[] = {'S','C','S','I','M','G','R','$',0}; + static const WCHAR hpscanW[] = {'H','P','S','C','A','N',0}; + static const WCHAR emmxxxx0W[] = {'E','M','M','X','X','X','X','0',0}; /* got it */ - if (!strcmp(DOSFS_Devices[i].name,"NUL")) + if (!strcmpiW(DOSFS_Devices[i].name, nulW)) return FILE_CreateFile( "/dev/null", access, FILE_SHARE_READ|FILE_SHARE_WRITE, sa, OPEN_EXISTING, 0, 0, TRUE, DRIVE_UNKNOWN ); - if (!strcmp(DOSFS_Devices[i].name,"CON")) { + if (!strcmpiW(DOSFS_Devices[i].name, conW)) { HANDLE to_dup; switch (access & (GENERIC_READ|GENERIC_WRITE)) { case GENERIC_READ: @@ -810,16 +933,16 @@ HANDLE DOSFS_OpenDevice( const char *name, DWORD access, DWORD attributes, LPSEC handle = 0; return handle; } - if (!strcmp(DOSFS_Devices[i].name,"SCSIMGR$") || - !strcmp(DOSFS_Devices[i].name,"HPSCAN") || - !strcmp(DOSFS_Devices[i].name,"EMMXXXX0")) + if (!strcmpiW(DOSFS_Devices[i].name, scsimgrW) || + !strcmpiW(DOSFS_Devices[i].name, hpscanW) || + !strcmpiW(DOSFS_Devices[i].name, emmxxxx0W)) { return FILE_CreateDevice( i, access, sa ); } if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) ) return handle; - FIXME("device open %s not supported (yet)\n",DOSFS_Devices[i].name); + FIXME("device open %s not supported (yet)\n", debugstr_w(DOSFS_Devices[i].name)); return 0; } } @@ -833,21 +956,21 @@ HANDLE DOSFS_OpenDevice( const char *name, DWORD access, DWORD attributes, LPSEC * * Get the drive specified by a given path name (DOS or Unix format). */ -static int DOSFS_GetPathDrive( const char **name ) +static int DOSFS_GetPathDrive( LPCWSTR *name ) { int drive; - const char *p = *name; + LPCWSTR p = *name; if (*p && (p[1] == ':')) { - drive = FILE_toupper(*p) - 'A'; + drive = toupperW(*p) - 'A'; *name += 2; } else if (*p == '/') /* Absolute Unix path? */ { - if ((drive = DRIVE_FindDriveRoot( name )) == -1) + if ((drive = DRIVE_FindDriveRootW( name )) == -1) { - MESSAGE("Warning: %s not accessible from a configured DOS drive\n", *name ); + MESSAGE("Warning: %s not accessible from a configured DOS drive\n", debugstr_w(*name) ); /* Assume it really was a DOS name */ drive = DRIVE_GetCurrentDrive(); } @@ -873,13 +996,16 @@ static int DOSFS_GetPathDrive( const char **name ) * The buffers pointed to by 'long_buf' and 'short_buf' must be * at least MAX_PATHNAME_LEN long. */ -BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) +BOOL DOSFS_GetFullName( LPCWSTR name, BOOL check_last, DOS_FULL_NAME *full ) { BOOL found; - UINT flags; - char *p_l, *p_s, *root; + UINT flags, codepage; + char *p_l, *root; + LPWSTR p_s; + static const WCHAR driveA_rootW[] = {'A',':','\\',0}; + static const WCHAR dos_rootW[] = {'\\',0}; - TRACE("%s (last=%d)\n", name, check_last ); + TRACE("%s (last=%d)\n", debugstr_w(name), check_last ); if ((!*name) || (*name=='\n')) { /* error code for Win98 */ @@ -889,13 +1015,14 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE; flags = DRIVE_GetFlags( full->drive ); + codepage = DRIVE_GetCodepage(full->drive); lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ), sizeof(full->long_name) ); if (full->long_name[1]) root = full->long_name + strlen(full->long_name); else root = full->long_name; /* root directory */ - strcpy( full->short_name, "A:\\" ); + strcpyW( full->short_name, driveA_rootW ); full->short_name[0] += full->drive; if ((*name == '\\') || (*name == '/')) /* Absolute path */ @@ -907,13 +1034,13 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ), sizeof(full->long_name) - (root - full->long_name) - 1 ); if (root[1]) *root = '/'; - lstrcpynA( full->short_name + 3, DRIVE_GetDosCwd( full->drive ), - sizeof(full->short_name) - 3 ); + lstrcpynW( full->short_name + 3, DRIVE_GetDosCwd( full->drive ), + sizeof(full->short_name)/sizeof(full->short_name[0]) - 3 ); } p_l = full->long_name[1] ? full->long_name + strlen(full->long_name) : full->long_name; - p_s = full->short_name[3] ? full->short_name + strlen(full->short_name) + p_s = full->short_name[3] ? full->short_name + strlenW(full->short_name) : full->short_name + 2; found = TRUE; @@ -942,7 +1069,7 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) /* Make sure buffers are large enough */ - if ((p_s >= full->short_name + sizeof(full->short_name) - 14) || + if ((p_s >= full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 14) || (p_l >= full->long_name + sizeof(full->long_name) - 1)) { SetLastError( ERROR_PATH_NOT_FOUND ); @@ -951,14 +1078,14 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) /* Get the long and short name matching the file name */ - if ((found = DOSFS_FindUnixName( full->long_name, name, p_l + 1, + if ((found = DOSFS_FindUnixName( full, name, p_l + 1, sizeof(full->long_name) - (p_l - full->long_name) - 1, p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) ))) { *p_l++ = '/'; p_l += strlen(p_l); *p_s++ = '\\'; - p_s += strlen(p_s); + p_s += strlenW(p_s); while (!IS_END_OF_NAME(*name)) name++; } else if (!check_last) @@ -966,15 +1093,17 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) *p_l++ = '/'; *p_s++ = '\\'; while (!IS_END_OF_NAME(*name) && - (p_s < full->short_name + sizeof(full->short_name) - 1) && + (p_s < full->short_name + sizeof(full->short_name)/sizeof(full->short_name[0]) - 1) && (p_l < full->long_name + sizeof(full->long_name) - 1)) { - *p_s++ = FILE_tolower(*name); + WCHAR wch; + *p_s++ = tolowerW(*name); /* If the drive is case-sensitive we want to create new */ /* files in lower-case otherwise we can't reopen them */ /* under the same short name. */ - if (flags & DRIVE_CASE_SENSITIVE) *p_l++ = FILE_tolower(*name); - else *p_l++ = *name; + if (flags & DRIVE_CASE_SENSITIVE) wch = tolowerW(*name); + else wch = *name; + p_l += WideCharToMultiByte(codepage, 0, &wch, 1, p_l, 2, NULL, NULL); name++; } /* Ignore trailing dots and spaces */ @@ -982,7 +1111,8 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) --p_l; --p_s; } - *p_l = *p_s = '\0'; + *p_l = '\0'; + *p_s = '\0'; } while ((*name == '\\') || (*name == '/')) name++; } @@ -1001,14 +1131,14 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) } } if (!full->long_name[0]) strcpy( full->long_name, "/" ); - if (!full->short_name[2]) strcpy( full->short_name + 2, "\\" ); - TRACE("returning %s = %s\n", full->long_name, full->short_name ); + if (!full->short_name[2]) strcpyW( full->short_name + 2, dos_rootW ); + TRACE("returning %s = %s\n", full->long_name, debugstr_w(full->short_name) ); return TRUE; } /*********************************************************************** - * GetShortPathNameA (KERNEL32.@) + * GetShortPathNameW (KERNEL32.@) * * NOTES * observed: @@ -1027,17 +1157,18 @@ BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) * - longpath and shortpath may have the same address * Peter Ganten, 1999 */ -DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, - DWORD shortlen ) +DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, DWORD shortlen ) { DOS_FULL_NAME full_name; - LPSTR tmpshortpath; + WCHAR tmpshortpath[MAX_PATHNAME_LEN]; + const WCHAR *p; DWORD sp = 0, lp = 0; - int tmplen, drive; + int drive; + DWORD tmplen; UINT flags; BOOL unixabsolute = *longpath == '/'; - TRACE("%s\n", debugstr_a(longpath)); + TRACE("%s\n", debugstr_w(longpath)); if (!longpath) { SetLastError(ERROR_INVALID_PARAMETER); @@ -1048,11 +1179,6 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, return 0; } - if ( ( tmpshortpath = HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) { - SetLastError ( ERROR_NOT_ENOUGH_MEMORY ); - return 0; - } - /* check for drive letter */ if (!unixabsolute && longpath[1] == ':' ) { tmpshortpath[0] = longpath[0]; @@ -1084,8 +1210,10 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, continue; } - tmplen = strcspn ( longpath + lp, "\\/" ); - lstrcpynA ( tmpshortpath+sp, longpath + lp, tmplen+1 ); + 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) ) ) { @@ -1096,8 +1224,8 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, /* Check if the file exists and use the existing file name */ if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) { - strcpy( tmpshortpath+sp, strrchr ( full_name.short_name, '\\' ) + 1 ); - sp += strlen ( tmpshortpath+sp ); + strcpyW(tmpshortpath + sp, strrchrW(full_name.short_name, '\\') + 1); + sp += strlenW(tmpshortpath + sp); lp += tmplen; continue; } @@ -1108,50 +1236,81 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, } tmpshortpath[sp] = 0; - lstrcpynA ( shortpath, tmpshortpath, shortlen ); - TRACE("returning %s\n", debugstr_a(shortpath) ); - tmplen = strlen ( tmpshortpath ); - HeapFree ( GetProcessHeap(), 0, tmpshortpath ); + tmplen = strlenW(tmpshortpath) + 1; + if (tmplen <= shortlen) + { + strcpyW(shortpath, tmpshortpath); + TRACE("returning %s\n", debugstr_w(shortpath)); + tmplen--; /* length without 0 */ + } return tmplen; } /*********************************************************************** - * GetShortPathNameW (KERNEL32.@) + * GetShortPathNameA (KERNEL32.@) */ -DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, - DWORD shortlen ) +DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen ) { - LPSTR longpathA, shortpathA; - DWORD ret = 0; + UNICODE_STRING longpathW; + WCHAR shortpathW[MAX_PATH]; + DWORD ret, retW; - longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, longpath ); - shortpathA = HeapAlloc ( GetProcessHeap(), 0, shortlen ); + if (!longpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } - ret = GetShortPathNameA ( longpathA, shortpathA, shortlen ); - if (shortlen > 0 && !MultiByteToWideChar( CP_ACP, 0, shortpathA, -1, shortpath, shortlen )) - shortpath[shortlen-1] = 0; - HeapFree( GetProcessHeap(), 0, longpathA ); - HeapFree( GetProcessHeap(), 0, shortpathA ); + 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; } /*********************************************************************** - * GetLongPathNameA (KERNEL32.@) + * GetLongPathNameW (KERNEL32.@) * * NOTES * observed (Win2000): * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 */ -DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, - DWORD longlen ) +DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) { DOS_FULL_NAME full_name; - char *p, *r, *ll, *ss; + const char *root; + LPWSTR p; + int drive; + UINT codepage; + DWORD ret, len = 0; if (!shortpath) { SetLastError(ERROR_INVALID_PARAMETER); @@ -1162,79 +1321,92 @@ DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, return 0; } + TRACE("%s,%p,%ld\n", debugstr_w(shortpath), longpath, longlen); + if(shortpath[0]=='\\' && shortpath[1]=='\\') { - ERR("UNC pathname %s\n",debugstr_a(shortpath)); - lstrcpynA( longpath, full_name.short_name, longlen ); - return lstrlenA(longpath); + 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; - lstrcpynA( longpath, full_name.short_name, longlen ); - /* Do some hackery to get the long filename. */ + root = full_name.long_name; + drive = DRIVE_FindDriveRoot(&root); + codepage = DRIVE_GetCodepage(drive); - if (longpath) { - ss=longpath+strlen(longpath); - ll=full_name.long_name+strlen(full_name.long_name); - p=NULL; - while (ss>=longpath) - { - /* FIXME: aren't we more paranoid, than needed? */ - while ((ss[0]=='\\') && (ss>=longpath)) ss--; - p=ss; - while ((ss[0]!='\\') && (ss>=longpath)) ss--; - if (ss>=longpath) - { - /* FIXME: aren't we more paranoid, than needed? */ - while ((ll[0]=='/') && (ll>=full_name.long_name)) ll--; - while ((ll[0]!='/') && (ll>=full_name.long_name)) ll--; - if (ll0) longlen -= (p-longpath); - lstrcpynA( p, ll , longlen); - - /* Now, change all '/' to '\' */ - for (r=p; r<(p+longlen); r++ ) - if (r[0]=='/') r[0]='\\'; - return strlen(longpath) - strlen(p) + longlen; - } + ret = MultiByteToWideChar(codepage, 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; } - - return strlen(longpath); + ret += len; + if (ret <= longlen) + { + longpath[0] = 'A' + drive; + longpath[1] = ':'; + MultiByteToWideChar(codepage, 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; } /*********************************************************************** - * GetLongPathNameW (KERNEL32.@) + * GetLongPathNameA (KERNEL32.@) */ -DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, - DWORD longlen ) +DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen ) { - DOS_FULL_NAME full_name; - DWORD ret = 0; - LPSTR shortpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, shortpath ); + UNICODE_STRING shortpathW; + WCHAR longpathW[MAX_PATH]; + DWORD ret, retW; - /* FIXME: is it correct to always return a fully qualified short path? */ - if (DOSFS_GetFullName( shortpathA, TRUE, &full_name )) + if (!shortpath) { - ret = strlen( full_name.short_name ); - if (longlen > 0 && !MultiByteToWideChar( CP_ACP, 0, full_name.long_name, -1, - longpath, longlen )) - longpath[longlen-1] = 0; + SetLastError(ERROR_INVALID_PARAMETER); + return 0; } - HeapFree( GetProcessHeap(), 0, shortpathA ); + + 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; } @@ -1248,20 +1420,29 @@ DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, * A test for GetFullPathName with many pathological cases * now gives identical output for Wine and OSR2 */ -static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, - BOOL unicode ) +static DWORD DOSFS_DoGetFullPathName( LPCWSTR name, DWORD len, LPWSTR result ) { DWORD ret; DOS_FULL_NAME full_name; - char *p,*q; + LPWSTR p, q; + char *p_l; const char * root; - char drivecur[]="c:."; - char driveletter=0; + 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]) return 0; + if (!name[0]) + { + SetLastError(ERROR_BAD_PATHNAME); + return 0; + } - TRACE("passed '%s'\n", name); + TRACE("passed %s\n", debugstr_w(name)); if (name[1]==':') /*drive letter given */ @@ -1271,17 +1452,18 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, if ((name[1]==':') && ((name[2]=='\\') || (name[2]=='/'))) /*absolute path given */ { - lstrcpynA(full_name.short_name,name,MAX_PATHNAME_LEN); - drive = (int)FILE_toupper(name[0]) - 'A'; + 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]=='/')) - strcpy(drivecur,"\\"); + strcpyW(drivecur, bkslashW); else - strcpy(drivecur,"."); + strcpyW(drivecur, dotW); if (!DOSFS_GetFullName( drivecur, FALSE, &full_name )) { @@ -1289,7 +1471,7 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, return 0; } /* find path that drive letter substitutes*/ - drive = (int)FILE_toupper(full_name.short_name[0]) -0x41; + drive = toupperW(full_name.short_name[0]) - 'A'; root= DRIVE_GetRoot(drive); if (!root) { @@ -1299,31 +1481,33 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, if (!strcmp(root,"/")) { /* we have just the last / and we need it. */ - p= full_name.long_name; + p_l = full_name.long_name; } else { - p= full_name.long_name +strlen(root); + p_l = full_name.long_name + strlen(root); } /* append long name (= unix name) to drive */ - lstrcpynA(full_name.short_name+2,p,MAX_PATHNAME_LEN-3); + MultiByteToWideChar(DRIVE_GetCodepage(drive), 0, p_l, -1, + full_name.short_name + 2, MAX_PATHNAME_LEN - 3); /* append name to treat */ - namelen= strlen(full_name.short_name); - p = (char*)name; + namelen= strlenW(full_name.short_name); + p = (LPWSTR)name; if (driveletter) - p += +2; /* skip drive name when appending */ - if (namelen +2 + strlen(p) > MAX_PATHNAME_LEN) + 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; - lstrcpynA(full_name.short_name +namelen,p,MAX_PATHNAME_LEN-namelen); + 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+strlen(full_name.short_name); + p < full_name.short_name + strlenW(full_name.short_name); p++) { if ( *p == '/' ) @@ -1331,40 +1515,40 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, } /* Use memmove, as areas overlap */ /* Delete .. */ - while ((p = strstr(full_name.short_name,"\\..\\"))) + while ((p = strstrW(full_name.short_name, updir_slashW))) { if (p > full_name.short_name+2) { *p = 0; - q = strrchr(full_name.short_name,'\\'); - memmove(q+1,p+4,strlen(p+4)+1); + 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,strlen(p+4)+1); + 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, - strlen(full_name.short_name+4)+1); + (strlenW(full_name.short_name+4)+1) * sizeof(WCHAR)); } /* Delete . */ - while ((p = strstr(full_name.short_name,"\\.\\"))) + while ((p = strstrW(full_name.short_name, curdirW))) { *(p+1) = 0; - memmove(p+1,p+3,strlen(p+3)+1); + 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 = FILE_toupper(*p); - namelen=strlen(full_name.short_name); - if (!strcmp(full_name.short_name+namelen-3,"\\..")) + 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 = strrchr(full_name.short_name,'\\'); + q = strrchrW(full_name.short_name, '\\'); *q =0; } if (full_name.short_name[namelen-1]=='.') @@ -1372,13 +1556,13 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, if (!driveletter) if (full_name.short_name[namelen-1]=='\\') full_name.short_name[(namelen--)-1] =0; - TRACE("got %s\n",full_name.short_name); + 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 = strlen(full_name.short_name); + ret = strlenW(full_name.short_name); if (ret >= len ) { /* don't touch anything when the buffer is not large enough */ @@ -1387,13 +1571,11 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, } if (result) { - if (unicode) - MultiByteToWideChar( CP_ACP, 0, full_name.short_name, -1, (LPWSTR)result, len ); - else - lstrcpynA( result, full_name.short_name, len ); + strncpyW( result, full_name.short_name, len ); + result[len - 1] = 0; /* ensure 0 termination */ } - TRACE("returning '%s'\n", full_name.short_name ); + TRACE("returning %s\n", debugstr_w(full_name.short_name) ); return ret; } @@ -1406,18 +1588,54 @@ static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, LPSTR *lastpart ) { - DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer, FALSE ); - if (ret && (ret<=len) && buffer && lastpart) - { - LPSTR p = buffer + strlen(buffer); + UNICODE_STRING nameW; + WCHAR bufferW[MAX_PATH]; + DWORD ret, retW; - if (*p != '\\') - { - while ((p > buffer + 2) && (*p != '\\')) p--; - *lastpart = p + 1; - } - else *lastpart = NULL; + 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; } @@ -1428,9 +1646,7 @@ DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, LPWSTR *lastpart ) { - LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); - DWORD ret = DOSFS_DoGetFullPathName( nameA, len, (LPSTR)buffer, TRUE ); - HeapFree( GetProcessHeap(), 0, nameA ); + DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer ); if (ret && (ret<=len) && buffer && lastpart) { LPWSTR p = buffer + strlenW(buffer); @@ -1449,12 +1665,21 @@ DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, * wine_get_unix_file_name (KERNEL32.@) Not a Windows API * * Return the full Unix file name for a given path. + * FIXME: convert dos file name to unicode */ BOOL WINAPI wine_get_unix_file_name( LPCSTR dos, LPSTR buffer, DWORD len ) { BOOL ret; DOS_FULL_NAME path; - if ((ret = DOSFS_GetFullName( dos, FALSE, &path ))) lstrcpynA( buffer, path.long_name, len ); + WCHAR dosW[MAX_PATHNAME_LEN]; + + MultiByteToWideChar(CP_ACP, 0, dos, -1, dosW, MAX_PATHNAME_LEN); + ret = DOSFS_GetFullName( dosW, FALSE, &path ); + if (ret && len) + { + strncpy( buffer, path.long_name, len ); + buffer[len - 1] = 0; /* ensure 0 termination */ + } return ret; } @@ -1462,16 +1687,16 @@ BOOL WINAPI wine_get_unix_file_name( LPCSTR dos, LPSTR buffer, DWORD len ) /*********************************************************************** * DOSFS_FindNextEx */ -static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) +static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry ) { DWORD attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY | FILE_ATTRIBUTE_SYMLINK; UINT flags = DRIVE_GetFlags( info->drive ); char *p, buffer[MAX_PATHNAME_LEN]; const char *drive_path; int drive_root; - LPCSTR long_name, short_name; + LPCWSTR long_name, short_name; BY_HANDLE_FILE_INFORMATION fileinfo; - char dos_name[13]; + WCHAR dos_name[13]; if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL) { @@ -1485,10 +1710,10 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) entry->dwReserved0 = 0; entry->dwReserved1 = 0; DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName ); - strcpy( entry->cAlternateFileName, entry->cFileName ); + strcpyW( entry->cAlternateFileName, entry->cFileName ); info->cur_pos++; TRACE("returning %s (%s) as label\n", - entry->cFileName, entry->cAlternateFileName); + debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName)); return 1; } @@ -1531,8 +1756,8 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) } /* Check the file attributes */ - - lstrcpynA( p, long_name, sizeof(buffer) - (int)(p - buffer) ); + WideCharToMultiByte(DRIVE_GetCodepage(info->drive), 0, long_name, -1, + p, sizeof(buffer) - (int)(p - buffer), NULL, NULL); if (!FILE_Stat( buffer, &fileinfo )) { WARN("can't stat %s\n", buffer); @@ -1541,9 +1766,11 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) if ((fileinfo.dwFileAttributes & FILE_ATTRIBUTE_SYMLINK) && (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + static const WCHAR wineW[] = {'w','i','n','e',0}; + static const WCHAR ShowDirSymlinksW[] = {'S','h','o','w','D','i','r','S','y','m','l','i','n','k','s',0}; static int show_dir_symlinks = -1; if (show_dir_symlinks == -1) - show_dir_symlinks = PROFILE_GetWineIniBool("wine", "ShowDirSymlinks", 0); + show_dir_symlinks = PROFILE_GetWineIniBool(wineW, ShowDirSymlinksW, 0); if (!show_dir_symlinks) continue; } @@ -1564,10 +1791,10 @@ static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE, !(flags & DRIVE_CASE_SENSITIVE) ); - lstrcpynA( entry->cFileName, long_name, sizeof(entry->cFileName) ); - if (!(flags & DRIVE_CASE_PRESERVING)) _strlwr( entry->cFileName ); + lstrcpynW( entry->cFileName, long_name, sizeof(entry->cFileName)/sizeof(entry->cFileName[0]) ); + if (!(flags & DRIVE_CASE_PRESERVING)) strlwrW( entry->cFileName ); TRACE("returning %s (%s) %02lx %ld\n", - entry->cFileName, entry->cAlternateFileName, + debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName), entry->dwFileAttributes, entry->nFileSizeLow ); return 1; } @@ -1592,26 +1819,38 @@ int DOSFS_FindNext( const char *path, const char *short_mask, int skip, WIN32_FIND_DATAA *entry ) { static FIND_FIRST_INFO info; - LPCSTR short_name, long_name; + LPCWSTR short_name, long_name; int count; + UNICODE_STRING short_maskW, long_maskW; + WIN32_FIND_DATAW entryW; _EnterWin16Lock(); + RtlCreateUnicodeStringFromAsciiz(&short_maskW, short_mask); + RtlCreateUnicodeStringFromAsciiz(&long_maskW, long_mask); + /* Check the cached directory */ - if (!(info.u.dos_dir && info.path == path && info.short_mask == short_mask - && info.long_mask == long_mask && info.drive == drive + 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; - info.long_mask = (LPSTR)long_mask; - info.short_mask = (LPSTR)short_mask; + 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( info.path ); + info.u.dos_dir = DOSFS_OpenDir( DRIVE_GetCodepage(drive), info.path ); + } + else + { + RtlFreeUnicodeString(&short_maskW); + RtlFreeUnicodeString(&long_maskW); } /* Skip to desired position */ @@ -1621,8 +1860,14 @@ int DOSFS_FindNext( const char *path, const char *short_mask, else break; - if (info.u.dos_dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, entry )) + 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; + } else count = 0; @@ -1638,10 +1883,10 @@ int DOSFS_FindNext( const char *path, const char *short_mask, } /************************************************************************* - * FindFirstFileExA (KERNEL32.@) + * FindFirstFileExW (KERNEL32.@) */ -HANDLE WINAPI FindFirstFileExA( - LPCSTR lpFileName, +HANDLE WINAPI FindFirstFileExW( + LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, @@ -1651,6 +1896,12 @@ HANDLE WINAPI FindFirstFileExA( HGLOBAL handle; FIND_FIRST_INFO *info; + if (!lpFileName) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0)) { FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags ); @@ -1661,7 +1912,11 @@ HANDLE WINAPI FindFirstFileExA( { case FindExInfoStandard: { - WIN32_FIND_DATAA * data = (WIN32_FIND_DATAA *) lpFindFileData; + WIN32_FIND_DATAW * data = (WIN32_FIND_DATAW *) lpFindFileData; + char *p; + INT long_mask_len; + UINT codepage; + data->dwReserved0 = data->dwReserved1 = 0x0; if (!lpFileName) return 0; if (lpFileName[0] == '\\' && lpFileName[1] == '\\') @@ -1686,25 +1941,28 @@ HANDLE WINAPI FindFirstFileExA( { DOS_FULL_NAME full_name; - if (!DOSFS_GetFullName( lpFileName, FALSE, &full_name )) break; - if (!(handle = GlobalAlloc(GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO)))) break; - info = (FIND_FIRST_INFO *)GlobalLock( handle ); - info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); - strcpy( info->path, full_name.long_name ); - info->long_mask = strrchr( info->path, '/' ); - *(info->long_mask++) = '\0'; - info->short_mask = NULL; - info->attr = 0xff; - if (lpFileName[0] && (lpFileName[1] == ':')) - info->drive = FILE_toupper(*lpFileName) - 'A'; - else info->drive = DRIVE_GetCurrentDrive(); - info->cur_pos = 0; + if (!DOSFS_GetFullName( lpFileName, FALSE, &full_name )) break; + if (!(handle = GlobalAlloc(GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO)))) break; + info = (FIND_FIRST_INFO *)GlobalLock( handle ); + info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); + strcpy( info->path, full_name.long_name ); - info->u.dos_dir = DOSFS_OpenDir( info->path ); - GlobalUnlock( handle ); + codepage = DRIVE_GetCodepage(full_name.drive); + p = strrchr( info->path, '/' ); + *p++ = '\0'; + long_mask_len = MultiByteToWideChar(codepage, 0, p, -1, NULL, 0); + info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) ); + MultiByteToWideChar(codepage, 0, p, -1, info->long_mask, long_mask_len); + + info->short_mask = NULL; + info->attr = 0xff; + info->drive = full_name.drive; + info->cur_pos = 0; + + info->u.dos_dir = DOSFS_OpenDir( codepage, info->path ); + GlobalUnlock( handle ); } - - if (!FindNextFileA( handle, data )) + if (!FindNextFileW( handle, data )) { FindClose( handle ); SetLastError( ERROR_NO_MORE_FILES ); @@ -1731,10 +1989,10 @@ HANDLE WINAPI FindFirstFileA( } /************************************************************************* - * FindFirstFileExW (KERNEL32.@) + * FindFirstFileExA (KERNEL32.@) */ -HANDLE WINAPI FindFirstFileExW( - LPCWSTR lpFileName, +HANDLE WINAPI FindFirstFileExA( + LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, @@ -1742,49 +2000,37 @@ HANDLE WINAPI FindFirstFileExW( DWORD dwAdditionalFlags) { HANDLE handle; - WIN32_FIND_DATAA dataA; - LPVOID _lpFindFileData; - LPSTR pathA; + WIN32_FIND_DATAA *dataA; + WIN32_FIND_DATAW dataW; + UNICODE_STRING pathW; - switch(fInfoLevelId) + if (!lpFileName) { - case FindExInfoStandard: - { - _lpFindFileData = &dataA; - } - break; - default: - FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId ); - return INVALID_HANDLE_VALUE; - } - - pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName ); - handle = FindFirstFileExA(pathA, fInfoLevelId, _lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags); - HeapFree( GetProcessHeap(), 0, pathA ); - if (handle == INVALID_HANDLE_VALUE) return handle; - - switch(fInfoLevelId) - { - case FindExInfoStandard: - { - WIN32_FIND_DATAW *dataW = (WIN32_FIND_DATAW*) lpFindFileData; - dataW->dwFileAttributes = dataA.dwFileAttributes; - dataW->ftCreationTime = dataA.ftCreationTime; - dataW->ftLastAccessTime = dataA.ftLastAccessTime; - dataW->ftLastWriteTime = dataA.ftLastWriteTime; - dataW->nFileSizeHigh = dataA.nFileSizeHigh; - dataW->nFileSizeLow = dataA.nFileSizeLow; - MultiByteToWideChar( CP_ACP, 0, dataA.cFileName, -1, - dataW->cFileName, sizeof(dataW->cFileName)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, dataA.cAlternateFileName, -1, - dataW->cAlternateFileName, - sizeof(dataW->cAlternateFileName)/sizeof(WCHAR) ); - } - break; - default: - FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId ); + SetLastError(ERROR_PATH_NOT_FOUND); return INVALID_HANDLE_VALUE; } + + if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags); + RtlFreeUnicodeString(&pathW); + if (handle == INVALID_HANDLE_VALUE) return handle; + + dataA = (WIN32_FIND_DATAA *) lpFindFileData; + dataA->dwFileAttributes = dataW.dwFileAttributes; + dataA->ftCreationTime = dataW.ftCreationTime; + dataA->ftLastAccessTime = dataW.ftLastAccessTime; + dataA->ftLastWriteTime = dataW.ftLastWriteTime; + dataA->nFileSizeHigh = dataW.nFileSizeHigh; + dataA->nFileSizeLow = dataW.nFileSizeLow; + WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1, + dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1, + dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL ); return handle; } @@ -1798,9 +2044,9 @@ HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData ) } /************************************************************************* - * FindNextFileA (KERNEL32.@) + * FindNextFileW (KERNEL32.@) */ -BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) +BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data ) { FIND_FIRST_INFO *info; BOOL ret = FALSE; @@ -1830,10 +2076,12 @@ BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) { DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL; HeapFree( GetProcessHeap(), 0, info->path ); - info->path = info->long_mask = NULL; + info->path = NULL; + HeapFree( GetProcessHeap(), 0, info->long_mask ); + info->long_mask = NULL; + goto done; } - else - ret = TRUE; + ret = TRUE; done: GlobalUnlock( handle ); if( !ret ) SetLastError( gle ); @@ -1842,23 +2090,23 @@ done: /************************************************************************* - * FindNextFileW (KERNEL32.@) + * FindNextFileA (KERNEL32.@) */ -BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data ) +BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) { - WIN32_FIND_DATAA dataA; - if (!FindNextFileA( handle, &dataA )) return FALSE; - data->dwFileAttributes = dataA.dwFileAttributes; - data->ftCreationTime = dataA.ftCreationTime; - data->ftLastAccessTime = dataA.ftLastAccessTime; - data->ftLastWriteTime = dataA.ftLastWriteTime; - data->nFileSizeHigh = dataA.nFileSizeHigh; - data->nFileSizeLow = dataA.nFileSizeLow; - MultiByteToWideChar( CP_ACP, 0, dataA.cFileName, -1, - data->cFileName, sizeof(data->cFileName)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, dataA.cAlternateFileName, -1, + WIN32_FIND_DATAW dataW; + if (!FindNextFileW( handle, &dataW )) return FALSE; + data->dwFileAttributes = dataW.dwFileAttributes; + data->ftCreationTime = dataW.ftCreationTime; + data->ftLastAccessTime = dataW.ftLastAccessTime; + data->ftLastWriteTime = dataW.ftLastWriteTime; + data->nFileSizeHigh = dataW.nFileSizeHigh; + data->nFileSizeLow = dataW.nFileSizeLow; + WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1, + data->cFileName, sizeof(data->cFileName), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1, data->cAlternateFileName, - sizeof(data->cAlternateFileName)/sizeof(WCHAR) ); + sizeof(data->cAlternateFileName), NULL, NULL ); return TRUE; } @@ -1877,6 +2125,7 @@ BOOL WINAPI FindClose( HANDLE handle ) { if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir ); if (info->path) HeapFree( GetProcessHeap(), 0, info->path ); + if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask ); } } __EXCEPT(page_fault) @@ -2399,26 +2648,35 @@ HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data ) DOS_FULL_NAME full_name; HGLOBAL16 handle; FIND_FIRST_INFO *info; + WCHAR pathW[MAX_PATH]; + char *p; + INT long_mask_len; + UINT codepage; data->dwReserved0 = data->dwReserved1 = 0x0; - if (!path) return 0; - if (!DOSFS_GetFullName( path, FALSE, &full_name )) + if (!path) return INVALID_HANDLE_VALUE16; + MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, MAX_PATH); + if (!DOSFS_GetFullName( pathW, FALSE, &full_name )) return INVALID_HANDLE_VALUE16; if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO) ))) return INVALID_HANDLE_VALUE16; info = (FIND_FIRST_INFO *)GlobalLock16( handle ); info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); strcpy( info->path, full_name.long_name ); - info->long_mask = strrchr( info->path, '/' ); - if (info->long_mask ) - *(info->long_mask++) = '\0'; + + codepage = DRIVE_GetCodepage(full_name.drive); + p = strrchr( info->path, '/' ); + *p++ = '\0'; + long_mask_len = MultiByteToWideChar(codepage, 0, p, -1, NULL, 0); + info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) ); + MultiByteToWideChar(codepage, 0, p, -1, info->long_mask, long_mask_len); + info->short_mask = NULL; info->attr = 0xff; - if (path[0] && (path[1] == ':')) info->drive = FILE_toupper(*path) - 'A'; - else info->drive = DRIVE_GetCurrentDrive(); + info->drive = full_name.drive; info->cur_pos = 0; - info->u.dos_dir = DOSFS_OpenDir( info->path ); + info->u.dos_dir = DOSFS_OpenDir( codepage, info->path ); GlobalUnlock16( handle ); if (!FindNextFile16( handle, data )) @@ -2436,28 +2694,48 @@ HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data ) BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data ) { FIND_FIRST_INFO *info; + WIN32_FIND_DATAW dataW; + BOOL ret = FALSE; + DWORD gle = ERROR_NO_MORE_FILES; if ((handle == INVALID_HANDLE_VALUE16) || !(info = (FIND_FIRST_INFO *)GlobalLock16( handle ))) { SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; + return ret; } - GlobalUnlock16( handle ); if (!info->path || !info->u.dos_dir) { - SetLastError( ERROR_NO_MORE_FILES ); - return FALSE; + goto done; } - if (!DOSFS_FindNextEx( info, data )) + if (!DOSFS_FindNextEx( info, &dataW )) { DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL; HeapFree( GetProcessHeap(), 0, info->path ); - info->path = info->long_mask = NULL; - SetLastError( ERROR_NO_MORE_FILES ); - return FALSE; + info->path = NULL; + HeapFree( GetProcessHeap(), 0, info->long_mask ); + info->long_mask = NULL; + goto done; } - return TRUE; + + ret = TRUE; + + data->dwFileAttributes = dataW.dwFileAttributes; + data->ftCreationTime = dataW.ftCreationTime; + data->ftLastAccessTime = dataW.ftLastAccessTime; + data->ftLastWriteTime = dataW.ftLastWriteTime; + data->nFileSizeHigh = dataW.nFileSizeHigh; + data->nFileSizeLow = dataW.nFileSizeLow; + WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1, + data->cFileName, sizeof(data->cFileName), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1, + data->cAlternateFileName, + sizeof(data->cAlternateFileName), NULL, NULL ); +done: + if( !ret ) SetLastError( gle ); + GlobalUnlock16( handle ); + + return ret; } /************************************************************************* @@ -2475,6 +2753,7 @@ BOOL16 WINAPI FindClose16( HANDLE16 handle ) } if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir ); if (info->path) HeapFree( GetProcessHeap(), 0, info->path ); + if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask ); GlobalUnlock16( handle ); GlobalFree16( handle ); return TRUE; diff --git a/files/drive.c b/files/drive.c index 94e151e1b8d..4a497259034 100644 --- a/files/drive.c +++ b/files/drive.c @@ -66,6 +66,7 @@ #include "heap.h" #include "msdos.h" #include "task.h" +#include "wine/unicode.h" #include "wine/library.h" #include "wine/server.h" #include "wine/debug.h" @@ -76,28 +77,29 @@ WINE_DECLARE_DEBUG_CHANNEL(file); typedef struct { char *root; /* root dir in Unix format without trailing / */ - char *dos_cwd; /* cwd in DOS format without leading or trailing \ */ + LPWSTR dos_cwd; /* cwd in DOS format without leading or trailing \ */ char *unix_cwd; /* cwd in Unix format without leading or trailing / */ char *device; /* raw device path */ - char label_conf[12]; /* drive label as cfg'd in wine config */ - char label_read[12]; /* drive label as read from device */ + WCHAR label_conf[12]; /* drive label as cfg'd in wine config */ + WCHAR label_read[12]; /* drive label as read from device */ DWORD serial_conf; /* drive serial number as cfg'd in wine config */ UINT type; /* drive type */ UINT flags; /* drive flags */ + UINT codepage; /* drive code page */ dev_t dev; /* unix device number */ ino_t ino; /* unix inode number */ } DOSDRIVE; -static const char * const DRIVE_Types[] = +static const WCHAR DRIVE_Types[][8] = { - "", /* DRIVE_UNKNOWN */ - "", /* DRIVE_NO_ROOT_DIR */ - "floppy", /* DRIVE_REMOVABLE */ - "hd", /* DRIVE_FIXED */ - "network", /* DRIVE_REMOTE */ - "cdrom", /* DRIVE_CDROM */ - "ramdisk" /* DRIVE_RAMDISK */ + { 0 }, /* DRIVE_UNKNOWN */ + { 0 }, /* DRIVE_NO_ROOT_DIR */ + {'f','l','o','p','p','y',0}, /* DRIVE_REMOVABLE */ + {'h','d',0}, /* DRIVE_FIXED */ + {'n','e','t','w','o','r','k',0}, /* DRIVE_REMOTE */ + {'c','d','r','o','m',0}, /* DRIVE_CDROM */ + {'r','a','m','d','i','s','k',0} /* DRIVE_RAMDISK */ }; @@ -105,19 +107,19 @@ static const char * const DRIVE_Types[] = typedef struct { - const char *name; + const WCHAR name[6]; UINT flags; } FS_DESCR; static const FS_DESCR DRIVE_Filesystems[] = { - { "unix", DRIVE_CASE_SENSITIVE | DRIVE_CASE_PRESERVING }, - { "msdos", DRIVE_SHORT_NAMES }, - { "dos", DRIVE_SHORT_NAMES }, - { "fat", DRIVE_SHORT_NAMES }, - { "vfat", DRIVE_CASE_PRESERVING }, - { "win95", DRIVE_CASE_PRESERVING }, - { NULL, 0 } + { {'u','n','i','x',0}, DRIVE_CASE_SENSITIVE | DRIVE_CASE_PRESERVING }, + { {'m','s','d','o','s',0}, DRIVE_SHORT_NAMES }, + { {'d','o','s',0}, DRIVE_SHORT_NAMES }, + { {'f','a','t',0}, DRIVE_SHORT_NAMES }, + { {'v','f','a','t',0}, DRIVE_CASE_PRESERVING }, + { {'w','i','n','9','5',0}, DRIVE_CASE_PRESERVING }, + { { 0 }, 0 } }; @@ -140,18 +142,22 @@ extern void CDROM_InitRegistry(int dev); /*********************************************************************** * DRIVE_GetDriveType */ -static UINT DRIVE_GetDriveType( const char *name ) +static UINT DRIVE_GetDriveType( LPCWSTR name ) { - char buffer[20]; + WCHAR buffer[20]; int i; + static const WCHAR TypeW[] = {'T','y','p','e',0}; + static const WCHAR hdW[] = {'h','d',0}; - PROFILE_GetWineIniString( name, "Type", "hd", buffer, sizeof(buffer) ); + PROFILE_GetWineIniString( name, TypeW, hdW, buffer, 20 ); + if(!buffer[0]) + strcpyW(buffer,hdW); for (i = 0; i < sizeof(DRIVE_Types)/sizeof(DRIVE_Types[0]); i++) { - if (!strcasecmp( buffer, DRIVE_Types[i] )) return i; + if (!strcmpiW( buffer, DRIVE_Types[i] )) return i; } - MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n", - name, buffer ); + MESSAGE("%s: unknown drive type %s, defaulting to 'hd'.\n", + debugstr_w(name), debugstr_w(buffer) ); return DRIVE_FIXED; } @@ -159,14 +165,14 @@ static UINT DRIVE_GetDriveType( const char *name ) /*********************************************************************** * DRIVE_GetFSFlags */ -static UINT DRIVE_GetFSFlags( const char *name, const char *value ) +static UINT DRIVE_GetFSFlags( LPCWSTR name, LPCWSTR value ) { const FS_DESCR *descr; - for (descr = DRIVE_Filesystems; descr->name; descr++) - if (!strcasecmp( value, descr->name )) return descr->flags; - MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n", - name, value ); + for (descr = DRIVE_Filesystems; *descr->name; descr++) + if (!strcmpiW( value, descr->name )) return descr->flags; + MESSAGE("%s: unknown filesystem type %s, defaulting to 'win95'.\n", + debugstr_w(name), debugstr_w(value) ); return DRIVE_CASE_PRESERVING; } @@ -177,32 +183,55 @@ static UINT DRIVE_GetFSFlags( const char *name, const char *value ) int DRIVE_Init(void) { int i, len, count = 0; - char name[] = "Drive A"; - char drive_env[] = "=A:"; - char path[MAX_PATHNAME_LEN]; - char buffer[80]; + WCHAR name[] = {'D','r','i','v','e',' ','A',0}; + WCHAR drive_env[] = {'=','A',':',0}; + WCHAR path[MAX_PATHNAME_LEN]; + WCHAR buffer[80]; struct stat drive_stat_buffer; - char *p; + WCHAR *p; DOSDRIVE *drive; + static const WCHAR PathW[] = {'P','a','t','h',0}; + static const WCHAR empty_strW[] = { 0 }; + static const WCHAR CodepageW[] = {'C','o','d','e','p','a','g','e',0}; + static const WCHAR LabelW[] = {'L','a','b','e','l',0}; + static const WCHAR SerialW[] = {'S','e','r','i','a','l',0}; + static const WCHAR zeroW[] = {'0',0}; + static const WCHAR def_serialW[] = {'1','2','3','4','5','6','7','8',0}; + static const WCHAR FilesystemW[] = {'F','i','l','e','s','y','s','t','e','m',0}; + static const WCHAR win95W[] = {'w','i','n','9','5',0}; + static const WCHAR DeviceW[] = {'D','e','v','i','c','e',0}; + static const WCHAR ReadVolInfoW[] = {'R','e','a','d','V','o','l','I','n','f','o',0}; + static const WCHAR FailReadOnlyW[] = {'F','a','i','l','R','e','a','d','O','n','l','y',0}; + static const WCHAR driveC_labelW[] = {'D','r','i','v','e',' ','C',' ',' ',' ',' ',0}; for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, name[6]++, drive++) { - PROFILE_GetWineIniString( name, "Path", "", path, sizeof(path)-1 ); + PROFILE_GetWineIniString( name, PathW, empty_strW, path, MAX_PATHNAME_LEN ); if (path[0]) { - p = path + strlen(path) - 1; + /* Get the code page number */ + PROFILE_GetWineIniString( name, CodepageW, zeroW, /* 0 == CP_ACP */ + buffer, 80 ); + drive->codepage = strtolW( buffer, NULL, 10 ); + + p = path + strlenW(path) - 1; while ((p > path) && (*p == '/')) *p-- = '\0'; if (path[0] == '/') { - drive->root = heap_strdup( path ); + len = WideCharToMultiByte(drive->codepage, 0, path, -1, NULL, 0, NULL, NULL); + drive->root = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(drive->codepage, 0, path, -1, drive->root, len, NULL, NULL); } else { /* relative paths are relative to config dir */ const char *config = wine_get_config_dir(); - drive->root = HeapAlloc( GetProcessHeap(), 0, strlen(config) + strlen(path) + 2 ); - sprintf( drive->root, "%s/%s", config, path ); + len = strlen(config); + len += WideCharToMultiByte(drive->codepage, 0, path, -1, NULL, 0, NULL, NULL) + 2; + drive->root = HeapAlloc( GetProcessHeap(), 0, len ); + len -= sprintf( drive->root, "%s/", config ); + WideCharToMultiByte(drive->codepage, 0, path, -1, drive->root + strlen(drive->root), len, NULL, NULL); } if (stat( drive->root, &drive_stat_buffer )) @@ -222,7 +251,7 @@ int DRIVE_Init(void) continue; } - drive->dos_cwd = heap_strdup( "" ); + drive->dos_cwd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(drive->dos_cwd[0])); drive->unix_cwd = heap_strdup( "" ); drive->type = DRIVE_GetDriveType( name ); drive->device = NULL; @@ -231,36 +260,38 @@ int DRIVE_Init(void) drive->ino = drive_stat_buffer.st_ino; /* Get the drive label */ - PROFILE_GetWineIniString( name, "Label", "", drive->label_conf, 12 ); - if ((len = strlen(drive->label_conf)) < 11) + PROFILE_GetWineIniString( name, LabelW, empty_strW, drive->label_conf, 12 ); + if ((len = strlenW(drive->label_conf)) < 11) { /* Pad label with spaces */ - memset( drive->label_conf + len, ' ', 11 - len ); + while(len < 11) drive->label_conf[len++] = ' '; drive->label_conf[11] = '\0'; } /* Get the serial number */ - PROFILE_GetWineIniString( name, "Serial", "12345678", - buffer, sizeof(buffer) ); - drive->serial_conf = strtoul( buffer, NULL, 16 ); + PROFILE_GetWineIniString( name, SerialW, def_serialW, buffer, 80 ); + drive->serial_conf = strtolW( buffer, NULL, 16 ); /* Get the filesystem type */ - PROFILE_GetWineIniString( name, "Filesystem", "win95", - buffer, sizeof(buffer) ); + PROFILE_GetWineIniString( name, FilesystemW, win95W, buffer, 80 ); drive->flags = DRIVE_GetFSFlags( name, buffer ); /* Get the device */ - PROFILE_GetWineIniString( name, "Device", "", - buffer, sizeof(buffer) ); + PROFILE_GetWineIniString( name, DeviceW, empty_strW, buffer, 80 ); if (buffer[0]) { int cd_fd; - drive->device = heap_strdup( buffer ); - if (PROFILE_GetWineIniBool( name, "ReadVolInfo", 1)) + len = WideCharToMultiByte(CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL); + drive->device = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(drive->codepage, 0, buffer, -1, drive->device, len, NULL, NULL); + + if (PROFILE_GetWineIniBool( name, ReadVolInfoW, 1)) drive->flags |= DRIVE_READ_VOL_INFO; + if (drive->type == DRIVE_CDROM) { - if ((cd_fd = open(buffer,O_RDONLY|O_NONBLOCK)) != -1) { + if ((cd_fd = open(drive->device, O_RDONLY|O_NONBLOCK)) != -1) + { CDROM_InitRegistry(cd_fd); close(cd_fd); } @@ -268,7 +299,7 @@ int DRIVE_Init(void) } /* Get the FailReadOnly flag */ - if (PROFILE_GetWineIniBool( name, "FailReadOnly", 0 )) + if (PROFILE_GetWineIniBool( name, FailReadOnlyW, 0 )) drive->flags |= DRIVE_FAIL_READ_ONLY; /* Make the first hard disk the current drive */ @@ -276,13 +307,13 @@ int DRIVE_Init(void) DRIVE_CurDrive = i; count++; - TRACE("%s: path=%s type=%s label='%s' serial=%08lx " - "flags=%08x dev=%x ino=%x\n", - name, drive->root, DRIVE_Types[drive->type], - drive->label_conf, drive->serial_conf, drive->flags, - (int)drive->dev, (int)drive->ino ); + TRACE("%s: path=%s type=%s label=%s serial=%08lx " + "flags=%08x codepage=%u dev=%x ino=%x\n", + debugstr_w(name), drive->root, debugstr_w(DRIVE_Types[drive->type]), + debugstr_w(drive->label_conf), drive->serial_conf, drive->flags, + drive->codepage, (int)drive->dev, (int)drive->ino ); } - else WARN("%s: not defined\n", name ); + else WARN("%s: not defined\n", debugstr_w(name) ); } if (!count) @@ -290,9 +321,9 @@ int DRIVE_Init(void) MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" ); /* Create a C drive pointing to Unix root dir */ DOSDrives[2].root = heap_strdup( "/" ); - DOSDrives[2].dos_cwd = heap_strdup( "" ); + DOSDrives[2].dos_cwd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSDrives[2].dos_cwd[0])); DOSDrives[2].unix_cwd = heap_strdup( "" ); - strcpy( DOSDrives[2].label_conf, "Drive C " ); + strcpyW( DOSDrives[2].label_conf, driveC_labelW ); DOSDrives[2].serial_conf = 12345678; DOSDrives[2].type = DRIVE_FIXED; DOSDrives[2].device = NULL; @@ -316,9 +347,9 @@ int DRIVE_Init(void) /* get current working directory info for all drives */ for (i = 0; i < MAX_DOS_DRIVES; i++, drive_env[1]++) { - if (!GetEnvironmentVariableA(drive_env, path, sizeof(path))) continue; + if (!GetEnvironmentVariableW(drive_env, path, MAX_PATHNAME_LEN)) continue; /* sanity check */ - if (toupper(path[0]) != drive_env[1] || path[1] != ':') continue; + if (toupperW(path[0]) != drive_env[1] || path[1] != ':') continue; DRIVE_Chdir( i, path + 2 ); } return 1; @@ -361,7 +392,6 @@ int DRIVE_SetCurrentDrive( int drive ) TRACE("%c:\n", 'A' + drive ); DRIVE_CurDrive = drive; if (pTask) pTask->curdrive = drive | 0x80; - chdir(DRIVE_GetUnixCwd(drive)); return 1; } @@ -373,6 +403,8 @@ int DRIVE_SetCurrentDrive( int drive ) * This can be used to translate a Unix path into a drive + DOS path. * Return value is the drive, or -1 on error. On success, path is modified * to point to the beginning of the DOS path. + * + * Note: path must be in the encoding of the underlying Unix file system. */ int DRIVE_FindDriveRoot( const char **path ) { @@ -436,6 +468,45 @@ int DRIVE_FindDriveRoot( const char **path ) } +/*********************************************************************** + * DRIVE_FindDriveRootW + * + * Unicode version of DRIVE_FindDriveRoot. + */ +int DRIVE_FindDriveRootW( LPCWSTR *path ) +{ + int drive, rootdrive = -1; + char buffer[MAX_PATHNAME_LEN]; + LPCWSTR p = *path; + int len, match_len = -1; + + for (drive = 0; drive < MAX_DOS_DRIVES; drive++) + { + if (!DOSDrives[drive].root || + (DOSDrives[drive].flags & DRIVE_DISABLED)) continue; + + WideCharToMultiByte(DOSDrives[drive].codepage, 0, *path, -1, + buffer, MAX_PATHNAME_LEN, NULL, NULL); + + len = strlen(DOSDrives[drive].root); + if(strncmp(DOSDrives[drive].root, buffer, len)) + continue; + if(len <= match_len) continue; + match_len = len; + rootdrive = drive; + p = *path + len; + } + + if (rootdrive != -1) + { + *path = p; + TRACE("%s -> drive %c:, root='%s', name=%s\n", + buffer, 'A' + rootdrive, DOSDrives[rootdrive].root, debugstr_w(*path) ); + } + return rootdrive; +} + + /*********************************************************************** * DRIVE_GetRoot */ @@ -449,7 +520,7 @@ const char * DRIVE_GetRoot( int drive ) /*********************************************************************** * DRIVE_GetDosCwd */ -const char * DRIVE_GetDosCwd( int drive ) +LPCWSTR DRIVE_GetDosCwd( int drive ) { TDB *pTask = TASK_GetCurrent(); if (!DRIVE_IsValid( drive )) return NULL; @@ -459,8 +530,11 @@ const char * DRIVE_GetDosCwd( int drive ) ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */ (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */ { + static const WCHAR rootW[] = {'\\',0}; + WCHAR curdirW[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, pTask->curdir, -1, curdirW, MAX_PATH); /* Perform the task-switch */ - if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" ); + if (!DRIVE_Chdir( drive, curdirW )) DRIVE_Chdir( drive, rootW ); DRIVE_LastTask = GetCurrentTask(); } return DOSDrives[drive].dos_cwd; @@ -480,8 +554,11 @@ const char * DRIVE_GetUnixCwd( int drive ) ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */ (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */ { + static const WCHAR rootW[] = {'\\',0}; + WCHAR curdirW[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, pTask->curdir, -1, curdirW, MAX_PATH); /* Perform the task-switch */ - if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" ); + if (!DRIVE_Chdir( drive, curdirW )) DRIVE_Chdir( drive, rootW ); DRIVE_LastTask = GetCurrentTask(); } return DOSDrives[drive].unix_cwd; @@ -661,18 +738,15 @@ int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff) */ static HANDLE CDROM_Open(int drive) { - char root[6]; - - strcpy(root, "\\\\.\\A:"); + WCHAR root[] = {'\\','\\','.','\\','A',':',0}; root[4] += drive; - - return CreateFileA(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + return CreateFileW(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); } /************************************************************************** * CDROM_Data_GetLabel [internal] */ -DWORD CDROM_Data_GetLabel(int drive, char *label) +DWORD CDROM_Data_GetLabel(int drive, WCHAR *label) { #define LABEL_LEN 32+1 int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK); @@ -702,12 +776,12 @@ DWORD CDROM_Data_GetLabel(int drive, char *label) ch = label_read[i]; label_read[i] = (ch << 8) | (ch >> 8); } - WideCharToMultiByte( CP_ACP, 0, label_read, -1, label, 12, NULL, NULL ); + strncpyW(label, label_read, 11); label[11] = 0; } else { - strncpy(label, (LPSTR)label_read, 11); + MultiByteToWideChar(DOSDrives[drive].codepage, 0, (LPSTR)label_read, -1, label, 11); label[11] = '\0'; } return 1; @@ -722,7 +796,7 @@ failure: /************************************************************************** * CDROM_GetLabel [internal] */ -static DWORD CDROM_GetLabel(int drive, char *label) +static DWORD CDROM_GetLabel(int drive, WCHAR *label) { HANDLE h = CDROM_Open(drive); CDROM_DISK_DATA cdd; @@ -739,8 +813,11 @@ static DWORD CDROM_GetLabel(int drive, char *label) ret = 0; break; case CDROM_DISK_AUDIO_TRACK: - strcpy(label, "Audio CD "); + { + static const WCHAR audioCD[] = {'A','u','d','i','o',' ','C','D',' ',' ',' ',0}; + strcpyW(label, audioCD); break; + } case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK: FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n"); /* fall through */ @@ -748,14 +825,14 @@ static DWORD CDROM_GetLabel(int drive, char *label) ret = 0; break; } - TRACE("CD: label is '%s'.\n", label); + TRACE("CD: label is %s\n", debugstr_w(label)); return ret; } /*********************************************************************** * DRIVE_GetLabel */ -const char * DRIVE_GetLabel( int drive ) +LPCWSTR DRIVE_GetLabel( int drive ) { int read = 0; char buff[DRIVE_SUPER]; @@ -778,7 +855,9 @@ const char * DRIVE_GetLabel( int drive ) offs = 0x2b; /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */ - if (offs != -1) memcpy(DOSDrives[drive].label_read,buff+offs,11); + if (offs != -1) + MultiByteToWideChar(DOSDrives[drive].codepage, 0, buff+offs, 11, + DOSDrives[drive].label_read, 11); DOSDrives[drive].label_read[11]='\0'; read = 1; } @@ -923,6 +1002,8 @@ DWORD DRIVE_GetSerialNumber( int drive ) DWORD serial = 0; char buff[DRIVE_SUPER]; + TRACE("drive %d, type = %d\n", drive, DOSDrives[drive].type); + if (!DRIVE_IsValid( drive )) return 0; if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO) @@ -980,7 +1061,7 @@ int DRIVE_SetSerialNumber( int drive, DWORD serial ) */ static UINT DRIVE_GetType( int drive ) { - if (!DRIVE_IsValid( drive )) return DRIVE_UNKNOWN; + if (!DRIVE_IsValid( drive )) return DRIVE_NO_ROOT_DIR; return DOSDrives[drive].type; } @@ -994,22 +1075,33 @@ UINT DRIVE_GetFlags( int drive ) return DOSDrives[drive].flags; } +/*********************************************************************** + * DRIVE_GetCodepage + */ +UINT DRIVE_GetCodepage( int drive ) +{ + if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0; + return DOSDrives[drive].codepage; +} + /*********************************************************************** * DRIVE_Chdir */ -int DRIVE_Chdir( int drive, const char *path ) +int DRIVE_Chdir( int drive, LPCWSTR path ) { DOS_FULL_NAME full_name; - char buffer[MAX_PATHNAME_LEN]; + WCHAR buffer[MAX_PATHNAME_LEN]; LPSTR unix_cwd; BY_HANDLE_FILE_INFORMATION info; TDB *pTask = TASK_GetCurrent(); - strcpy( buffer, "A:" ); - buffer[0] += drive; - TRACE("(%s,%s)\n", buffer, path ); - lstrcpynA( buffer + 2, path, sizeof(buffer) - 2 ); + buffer[0] = 'A' + drive; + buffer[1] = ':'; + buffer[2] = 0; + TRACE("(%s,%s)\n", debugstr_w(buffer), debugstr_w(path) ); + strncpyW( buffer + 2, path, MAX_PATHNAME_LEN - 2 ); + buffer[MAX_PATHNAME_LEN - 1] = 0; /* ensure 0 termination */ if (!DOSFS_GetFullName( buffer, TRUE, &full_name )) return 0; if (!FILE_Stat( full_name.long_name, &info )) return 0; @@ -1022,20 +1114,20 @@ int DRIVE_Chdir( int drive, const char *path ) while (*unix_cwd == '/') unix_cwd++; TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n", - 'A' + drive, unix_cwd, full_name.short_name + 3 ); + 'A' + drive, unix_cwd, debugstr_w(full_name.short_name + 3) ); HeapFree( GetProcessHeap(), 0, DOSDrives[drive].dos_cwd ); HeapFree( GetProcessHeap(), 0, DOSDrives[drive].unix_cwd ); - DOSDrives[drive].dos_cwd = heap_strdup( full_name.short_name + 3 ); + DOSDrives[drive].dos_cwd = HeapAlloc(GetProcessHeap(), 0, (strlenW(full_name.short_name) - 2) * sizeof(WCHAR)); + strcpyW(DOSDrives[drive].dos_cwd, full_name.short_name + 3); DOSDrives[drive].unix_cwd = heap_strdup( unix_cwd ); if (pTask && (pTask->curdrive & 0x80) && ((pTask->curdrive & ~0x80) == drive)) { - lstrcpynA( pTask->curdir, full_name.short_name + 2, - sizeof(pTask->curdir) ); + WideCharToMultiByte(CP_ACP, 0, full_name.short_name + 2, -1, + pTask->curdir, sizeof(pTask->curdir), NULL, NULL); DRIVE_LastTask = GetCurrentTask(); - chdir(unix_cwd); /* Only change if on current drive */ } return 1; } @@ -1103,7 +1195,8 @@ int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive ) } new->root = heap_strdup( old->root ); - new->dos_cwd = heap_strdup( old->dos_cwd ); + new->dos_cwd = HeapAlloc(GetProcessHeap(), 0, (strlenW(old->dos_cwd) + 1) * sizeof(WCHAR)); + strcpyW(new->dos_cwd, old->dos_cwd); new->unix_cwd = heap_strdup( old->unix_cwd ); new->device = heap_strdup( old->device ); memcpy ( new->label_conf, old->label_conf, 12 ); @@ -1198,7 +1291,7 @@ static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size, if (!DRIVE_IsValid(drive)) { - SetLastError( ERROR_INVALID_DRIVE ); + SetLastError( ERROR_PATH_NOT_FOUND ); return 0; } @@ -1238,18 +1331,18 @@ static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size, * Despite the API description, return required length including the * terminating null when buffer too small. This is the real behaviour. */ - -static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPSTR buf ) +static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPWSTR buf ) { UINT ret; - const char *s = DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ); + LPCWSTR dos_cwd = DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ); + static const WCHAR driveA_rootW[] = {'A',':','\\',0}; - assert(s); - ret = strlen(s) + 3; /* length of WHOLE current directory */ + ret = strlenW(dos_cwd) + 3; /* length of WHOLE current directory */ if (ret >= buflen) return ret + 1; - lstrcpynA( buf, "A:\\", min( 4u, buflen ) ); - if (buflen) buf[0] += DRIVE_GetCurrentDrive(); - if (buflen > 3) lstrcpynA( buf + 3, s, buflen - 3 ); + + strcpyW( buf, driveA_rootW ); + buf[0] += DRIVE_GetCurrentDrive(); + strcatW( buf, dos_cwd ); return ret; } @@ -1263,18 +1356,25 @@ static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPSTR buf ) char *DRIVE_BuildEnv(void) { int i, length = 0; - const char *cwd[MAX_DOS_DRIVES]; + LPCWSTR cwd[MAX_DOS_DRIVES]; char *env, *p; for (i = 0; i < MAX_DOS_DRIVES; i++) { - if ((cwd[i] = DRIVE_GetDosCwd(i)) && cwd[i][0]) length += strlen(cwd[i]) + 8; + if ((cwd[i] = DRIVE_GetDosCwd(i)) && cwd[i][0]) + length += WideCharToMultiByte(DRIVE_GetCodepage(i), 0, + cwd[i], -1, NULL, 0, NULL, NULL) + 7; } if (!(env = HeapAlloc( GetProcessHeap(), 0, length+1 ))) return NULL; for (i = 0, p = env; i < MAX_DOS_DRIVES; i++) { if (cwd[i] && cwd[i][0]) - p += sprintf( p, "=%c:=%c:\\%s", 'A'+i, 'A'+i, cwd[i] ) + 1; + { + *p++ = '='; *p++ = 'A' + i; *p++ = ':'; + *p++ = '='; *p++ = 'A' + i; *p++ = ':'; *p++ = '\\'; + WideCharToMultiByte(DRIVE_GetCodepage(i), 0, cwd[i], -1, p, 0x7fffffff, NULL, NULL); + p += strlen(p) + 1; + } } *p = 0; return env; @@ -1294,7 +1394,7 @@ BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors, /*********************************************************************** - * GetDiskFreeSpaceA (KERNEL32.@) + * GetDiskFreeSpaceW (KERNEL32.@) * * Fails if expression resulting from current drive's dir and "root" * is not a root dir of the target drive. @@ -1320,27 +1420,38 @@ BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors, * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\") * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST") */ -BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors, +BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors, LPDWORD sector_bytes, LPDWORD free_clusters, LPDWORD total_clusters ) { int drive, sec_size; ULARGE_INTEGER size,available; - LPCSTR path; + LPCWSTR path; DWORD cluster_sec; - if ((!root) || (strcmp(root,"\\") == 0)) + TRACE("%s,%p,%p,%p,%p\n", debugstr_w(root), cluster_sectors, sector_bytes, + free_clusters, total_clusters); + + if (!root || root[0] == '\\' || root[0] == '/') drive = DRIVE_GetCurrentDrive(); else - if ( (strlen(root) >= 2) && (root[1] == ':')) /* root contains drive tag */ + if (root[0] && root[1] == ':') /* root contains drive tag */ { - drive = toupper(root[0]) - 'A'; + drive = toupperW(root[0]) - 'A'; path = &root[2]; if (path[0] == '\0') + { path = DRIVE_GetDosCwd(drive); + if (!path) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return FALSE; + } + } else if (path[0] == '\\') path++; + if (path[0]) /* oops, we are in a subdir */ { SetLastError(ERROR_INVALID_NAME); @@ -1349,7 +1460,10 @@ BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors, } else { - SetLastError(ERROR_INVALID_NAME); + if (!root[0]) + SetLastError(ERROR_PATH_NOT_FOUND); + else + SetLastError(ERROR_INVALID_NAME); return FALSE; } @@ -1386,19 +1500,30 @@ BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors, /*********************************************************************** - * GetDiskFreeSpaceW (KERNEL32.@) + * GetDiskFreeSpaceA (KERNEL32.@) */ -BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors, +BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors, LPDWORD sector_bytes, LPDWORD free_clusters, LPDWORD total_clusters ) { - LPSTR xroot; - BOOL ret; + UNICODE_STRING rootW; + BOOL ret = FALSE; + + if (root) + { + if(!RtlCreateUnicodeStringFromAsciiz(&rootW, root)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + } + else + rootW.Buffer = NULL; + + ret = GetDiskFreeSpaceW(rootW.Buffer, cluster_sectors, sector_bytes, + free_clusters, total_clusters ); + RtlFreeUnicodeString(&rootW); - xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root); - ret = GetDiskFreeSpaceA( xroot,cluster_sectors, sector_bytes, - free_clusters, total_clusters ); - HeapFree( GetProcessHeap(), 0, xroot ); return ret; } @@ -1516,7 +1641,7 @@ UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of driv /*********************************************************************** - * GetDriveTypeA (KERNEL32.@) + * GetDriveTypeW (KERNEL32.@) * * Returns the type of the disk drive specified. If root is NULL the * root of the current directory is used. @@ -1533,34 +1658,49 @@ UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of driv * DRIVE_CDROM CDROM drive * DRIVE_RAMDISK virtual disk in RAM */ -UINT WINAPI GetDriveTypeA(LPCSTR root) /* [in] String describing drive */ +UINT WINAPI GetDriveTypeW(LPCWSTR root) /* [in] String describing drive */ { int drive; - TRACE("(%s)\n", debugstr_a(root)); + TRACE("(%s)\n", debugstr_w(root)); if (NULL == root) drive = DRIVE_GetCurrentDrive(); else { if ((root[1]) && (root[1] != ':')) { - WARN("invalid root %s\n", debugstr_a(root)); + WARN("invalid root %s\n", debugstr_w(root)); return DRIVE_NO_ROOT_DIR; } - drive = toupper(root[0]) - 'A'; + drive = toupperW(root[0]) - 'A'; } return DRIVE_GetType(drive); } /*********************************************************************** - * GetDriveTypeW (KERNEL32.@) + * GetDriveTypeA (KERNEL32.@) */ -UINT WINAPI GetDriveTypeW( LPCWSTR root ) +UINT WINAPI GetDriveTypeA( LPCSTR root ) { - LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, root ); - UINT ret = GetDriveTypeA( xpath ); - HeapFree( GetProcessHeap(), 0, xpath ); + UNICODE_STRING rootW; + UINT ret = 0; + + if (root) + { + if( !RtlCreateUnicodeStringFromAsciiz(&rootW, root)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + else + rootW.Buffer = NULL; + + ret = GetDriveTypeW(rootW.Buffer); + + RtlFreeUnicodeString(&rootW); return ret; + } @@ -1569,39 +1709,60 @@ UINT WINAPI GetDriveTypeW( LPCWSTR root ) */ UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf ) { - return (UINT16)DRIVE_GetCurrentDirectory(buflen, buf); + WCHAR cur_dirW[MAX_PATH]; + + DRIVE_GetCurrentDirectory(MAX_PATH, cur_dirW); + return (UINT16)WideCharToMultiByte(CP_ACP, 0, cur_dirW, -1, buf, buflen, NULL, NULL); } -/*********************************************************************** - * GetCurrentDirectoryA (KERNEL32.@) - */ -UINT WINAPI GetCurrentDirectoryA( UINT buflen, LPSTR buf ) -{ - UINT ret; - char longname[MAX_PATHNAME_LEN]; - char shortname[MAX_PATHNAME_LEN]; - ret = DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN, shortname); - if ( ret > MAX_PATHNAME_LEN ) { - ERR_(file)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret ); - return ret; - } - GetLongPathNameA(shortname, longname, MAX_PATHNAME_LEN); - ret = strlen( longname ) + 1; - if (ret > buflen) return ret; - strcpy(buf, longname); - return ret - 1; -} - /*********************************************************************** * GetCurrentDirectoryW (KERNEL32.@) */ UINT WINAPI GetCurrentDirectoryW( UINT buflen, LPWSTR buf ) { - LPSTR xpath = HeapAlloc( GetProcessHeap(), 0, buflen+1 ); - UINT ret = GetCurrentDirectoryA( buflen, xpath ); - if (ret < buflen) ret = MultiByteToWideChar( CP_ACP, 0, xpath, -1, buf, buflen ) - 1; - HeapFree( GetProcessHeap(), 0, xpath ); + UINT ret; + WCHAR longname[MAX_PATHNAME_LEN]; + WCHAR shortname[MAX_PATHNAME_LEN]; + + ret = DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN, shortname); + if ( ret > MAX_PATHNAME_LEN ) { + ERR_(file)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret ); + return ret; + } + GetLongPathNameW(shortname, longname, MAX_PATHNAME_LEN); + ret = strlenW( longname ) + 1; + if (ret > buflen) return ret; + strcpyW(buf, longname); + return ret - 1; +} + +/*********************************************************************** + * GetCurrentDirectoryA (KERNEL32.@) + */ +UINT WINAPI GetCurrentDirectoryA( UINT buflen, LPSTR buf ) +{ + WCHAR bufferW[MAX_PATH]; + DWORD ret, retW; + + retW = GetCurrentDirectoryW(MAX_PATH, bufferW); + + 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 (buflen >= ret) + { + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buf, buflen, NULL, NULL); + ret--; /* length without 0 */ + } + } return ret; } @@ -1616,19 +1777,20 @@ BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir ) /*********************************************************************** - * SetCurrentDirectoryA (KERNEL32.@) + * SetCurrentDirectoryW (KERNEL32.@) */ -BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir ) +BOOL WINAPI SetCurrentDirectoryW( LPCWSTR dir ) { int drive, olddrive = DRIVE_GetCurrentDrive(); - if (!dir) { - ERR_(file)("(NULL)!\n"); + if (!dir) + { + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (dir[0] && (dir[1]==':')) { - drive = toupper( *dir ) - 'A'; + drive = toupperW( *dir ) - 'A'; dir += 2; } else @@ -1638,6 +1800,7 @@ BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir ) sets pTask->curdir only if pTask->curdrive is drive */ if (!(DRIVE_SetCurrentDrive( drive ))) return FALSE; + /* FIXME: what about empty strings? Add a \\ ? */ if (!DRIVE_Chdir( drive, dir )) { DRIVE_SetCurrentDrive(olddrive); @@ -1648,14 +1811,27 @@ BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir ) /*********************************************************************** - * SetCurrentDirectoryW (KERNEL32.@) + * SetCurrentDirectoryA (KERNEL32.@) */ -BOOL WINAPI SetCurrentDirectoryW( LPCWSTR dirW ) +BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir ) { - LPSTR dir = HEAP_strdupWtoA( GetProcessHeap(), 0, dirW ); - BOOL res = SetCurrentDirectoryA( dir ); - HeapFree( GetProcessHeap(), 0, dir ); - return res; + UNICODE_STRING dirW; + BOOL ret = FALSE; + + if (!dir) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&dirW, dir)) + { + ret = SetCurrentDirectoryW(dirW.Buffer); + RtlFreeUnicodeString(&dirW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return ret; } @@ -1733,33 +1909,34 @@ DWORD WINAPI GetLogicalDrives(void) /*********************************************************************** - * GetVolumeInformationA (KERNEL32.@) + * GetVolumeInformationW (KERNEL32.@) */ -BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label, +BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len, DWORD *serial, DWORD *filename_len, DWORD *flags, - LPSTR fsname, DWORD fsname_len ) + LPWSTR fsname, DWORD fsname_len ) { int drive; - char *cp; + LPWSTR cp; /* FIXME, SetLastError()s missing */ if (!root) drive = DRIVE_GetCurrentDrive(); else { - if ((root[1]) && (root[1] != ':')) + if (root[0] && root[1] != ':') { - WARN("invalid root '%s'\n",root); + WARN("invalid root %s\n", debugstr_w(root)); return FALSE; } - drive = toupper(root[0]) - 'A'; + drive = toupperW(root[0]) - 'A'; } if (!DRIVE_IsValid( drive )) return FALSE; - if (label) + if (label && label_len) { - lstrcpynA( label, DRIVE_GetLabel(drive), label_len ); - cp = label + strlen(label); + strncpyW( label, DRIVE_GetLabel(drive), label_len ); + label[label_len - 1] = 0; /* ensure 0 termination */ + cp = label + strlenW(label); while (cp != label && *(cp-1) == ' ') cp--; *cp = '\0'; } @@ -1782,46 +1959,59 @@ BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label, if (DOSDrives[drive].flags & DRIVE_CASE_PRESERVING) *flags|=FS_CASE_IS_PRESERVED; } - if (fsname) { + if (fsname && fsname_len) + { /* Diablo checks that return code ... */ if (DOSDrives[drive].type == DRIVE_CDROM) - lstrcpynA( fsname, "CDFS", fsname_len ); + { + static const WCHAR cdfsW[] = {'C','D','F','S',0}; + strncpyW( fsname, cdfsW, fsname_len ); + } else - lstrcpynA( fsname, "FAT", fsname_len ); + { + static const WCHAR fatW[] = {'F','A','T',0}; + strncpyW( fsname, fatW, fsname_len ); + } + fsname[fsname_len - 1] = 0; /* ensure 0 termination */ } return TRUE; } /*********************************************************************** - * GetVolumeInformationW (KERNEL32.@) + * GetVolumeInformationA (KERNEL32.@) */ -BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, +BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label, DWORD label_len, DWORD *serial, DWORD *filename_len, DWORD *flags, - LPWSTR fsname, DWORD fsname_len ) + LPSTR fsname, DWORD fsname_len ) { - LPSTR xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root ); - LPSTR xvolname = label ? HeapAlloc(GetProcessHeap(),0,label_len) : NULL; - LPSTR xfsname = fsname ? HeapAlloc(GetProcessHeap(),0,fsname_len) : NULL; - BOOL ret = GetVolumeInformationA( xroot, xvolname, label_len, serial, - filename_len, flags, xfsname, - fsname_len ); - if (ret) + UNICODE_STRING rootW; + LPWSTR labelW, fsnameW; + BOOL ret; + + if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root); + else rootW.Buffer = NULL; + labelW = label ? HeapAlloc(GetProcessHeap(), 0, label_len * sizeof(WCHAR)) : NULL; + fsnameW = fsname ? HeapAlloc(GetProcessHeap(), 0, fsname_len * sizeof(WCHAR)) : NULL; + + if ((ret = GetVolumeInformationW(rootW.Buffer, labelW, label_len, serial, + filename_len, flags, fsnameW, fsname_len))) { - if (label) MultiByteToWideChar( CP_ACP, 0, xvolname, -1, label, label_len ); - if (fsname) MultiByteToWideChar( CP_ACP, 0, xfsname, -1, fsname, fsname_len ); + if (label) WideCharToMultiByte(CP_ACP, 0, labelW, -1, label, label_len, NULL, NULL); + if (fsname) WideCharToMultiByte(CP_ACP, 0, fsnameW, -1, fsname, fsname_len, NULL, NULL); } - HeapFree( GetProcessHeap(), 0, xroot ); - HeapFree( GetProcessHeap(), 0, xvolname ); - HeapFree( GetProcessHeap(), 0, xfsname ); + + RtlFreeUnicodeString(&rootW); + if (labelW) HeapFree( GetProcessHeap(), 0, labelW ); + if (fsnameW) HeapFree( GetProcessHeap(), 0, fsnameW ); return ret; } /*********************************************************************** - * SetVolumeLabelA (KERNEL32.@) + * SetVolumeLabelW (KERNEL32.@) */ -BOOL WINAPI SetVolumeLabelA( LPCSTR root, LPCSTR volname ) +BOOL WINAPI SetVolumeLabelW( LPCWSTR root, LPCWSTR volname ) { int drive; @@ -1832,32 +2022,37 @@ BOOL WINAPI SetVolumeLabelA( LPCSTR root, LPCSTR volname ) { if ((root[1]) && (root[1] != ':')) { - WARN("invalid root '%s'\n",root); + WARN("invalid root %s\n", debugstr_w(root)); return FALSE; } - drive = toupper(root[0]) - 'A'; + drive = toupperW(root[0]) - 'A'; } if (!DRIVE_IsValid( drive )) return FALSE; /* some copy protection stuff check this */ if (DOSDrives[drive].type == DRIVE_CDROM) return FALSE; - FIXME("(%s,%s),stub!\n", root, volname); + strncpyW(DOSDrives[drive].label_conf, volname, 12); + DOSDrives[drive].label_conf[12 - 1] = 0; /* ensure 0 termination */ return TRUE; } /*********************************************************************** - * SetVolumeLabelW (KERNEL32.@) + * SetVolumeLabelA (KERNEL32.@) */ -BOOL WINAPI SetVolumeLabelW(LPCWSTR rootpath,LPCWSTR volname) +BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname) { - LPSTR xroot, xvol; + UNICODE_STRING rootW, volnameW; BOOL ret; - xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath); - xvol = HEAP_strdupWtoA( GetProcessHeap(), 0, volname); - ret = SetVolumeLabelA( xroot, xvol ); - HeapFree( GetProcessHeap(), 0, xroot ); - HeapFree( GetProcessHeap(), 0, xvol ); + if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root); + else rootW.Buffer = NULL; + if (volname) RtlCreateUnicodeStringFromAsciiz(&volnameW, volname); + else volnameW.Buffer = NULL; + + ret = SetVolumeLabelW( rootW.Buffer, volnameW.Buffer ); + + RtlFreeUnicodeString(&rootW); + RtlFreeUnicodeString(&volnameW); return ret; } diff --git a/files/file.c b/files/file.c index f962cec769c..214f3f68ba8 100644 --- a/files/file.c +++ b/files/file.c @@ -58,6 +58,8 @@ #include "winerror.h" #include "windef.h" #include "winbase.h" +#include "winreg.h" +#include "ntddk.h" #include "wine/winbase16.h" #include "wine/server.h" @@ -69,6 +71,7 @@ #include "wincon.h" #include "smb.h" +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(file); @@ -193,13 +196,10 @@ static void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing ) */ int FILE_strcasecmp( const char *str1, const char *str2 ) { - for (;;) - { - int ret = FILE_toupper(*str1) - FILE_toupper(*str2); - if (ret || !*str1) return ret; - str1++; - str2++; - } + int ret = 0; + for ( ; ; str1++, str2++) + if ((ret = FILE_toupper(*str1) - FILE_toupper(*str2)) || !*str1) break; + return ret; } @@ -453,7 +453,18 @@ HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing, } } - if (err) SetLastError( RtlNtStatusToDosError(err) ); + if (err) + { + /* In the case file creation was rejected due to CREATE_NEW flag + * was specified and file with that name already exists, correct + * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS. + * Note: RtlNtStatusToDosError is not the subject to blame here. + */ + if (err == STATUS_OBJECT_NAME_COLLISION) + SetLastError( ERROR_FILE_EXISTS ); + else + SetLastError( RtlNtStatusToDosError(err) ); + } if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError()); return ret; @@ -483,13 +494,12 @@ HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa return ret; } -static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access) +static HANDLE FILE_OpenPipe(LPCWSTR name, DWORD access) { - WCHAR buffer[MAX_PATH]; HANDLE ret; DWORD len = 0; - if (name && !(len = MultiByteToWideChar( CP_ACP, 0, name, strlen(name), buffer, MAX_PATH ))) + if (name && (len = strlenW(name)) > MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; @@ -498,7 +508,7 @@ static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access) { req->access = access; SetLastError(0); - wine_server_add_data( req, buffer, len * sizeof(WCHAR) ); + wine_server_add_data( req, name, len * sizeof(WCHAR) ); wine_server_call_err( req ); ret = reply->handle; } @@ -508,7 +518,7 @@ static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access) } /************************************************************************* - * CreateFileA [KERNEL32.@] Creates or opens a file or other object + * CreateFileW [KERNEL32.@] Creates or opens a file or other object * * Creates or opens an object, and returns a handle that can be used to * access that object. @@ -535,19 +545,24 @@ static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access) * Doesn't support character devices, template files, or a * lot of the 'attributes' flags yet. */ -HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, +HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template ) { DOS_FULL_NAME full_name; HANDLE ret; + static const WCHAR bkslashes_with_question_markW[] = {'\\','\\','?','\\',0}; + static const WCHAR bkslashes_with_dotW[] = {'\\','\\','.','\\',0}; + static const WCHAR bkslashesW[] = {'\\','\\',0}; + static const WCHAR coninW[] = {'C','O','N','I','N','$',0}; + static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0}; if (!filename) { SetLastError( ERROR_INVALID_PARAMETER ); return INVALID_HANDLE_VALUE; } - TRACE("%s %s%s%s%s%s%s%s\n",filename, + TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename), ((access & GENERIC_READ)==GENERIC_READ)?"GENERIC_READ ":"", ((access & GENERIC_WRITE)==GENERIC_WRITE)?"GENERIC_WRITE ":"", (!access)?"QUERY_ACCESS ":"", @@ -558,30 +573,33 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, (creation ==CREATE_ALWAYS)?"CREATE_ALWAYS ": (creation ==OPEN_EXISTING)?"OPEN_EXISTING ": (creation ==OPEN_ALWAYS)?"OPEN_ALWAYS ": - (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":""); + (creation ==TRUNCATE_EXISTING)?"TRUNCATE_EXISTING ":"", attributes); /* If the name starts with '\\?\', ignore the first 4 chars. */ - if (!strncmp(filename, "\\\\?\\", 4)) + if (!strncmpW(filename, bkslashes_with_question_markW, 4)) { + static const WCHAR uncW[] = {'U','N','C','\\',0}; filename += 4; - if (!strncmp(filename, "UNC\\", 4)) + if (!strncmpiW(filename, uncW, 4)) { - FIXME("UNC name (%s) not supported.\n", filename ); + FIXME("UNC name (%s) not supported.\n", debugstr_w(filename) ); SetLastError( ERROR_PATH_NOT_FOUND ); return INVALID_HANDLE_VALUE; } } - if (!strncmp(filename, "\\\\.\\", 4)) { - if(!strncasecmp(&filename[4],"pipe\\",5)) + if (!strncmpW(filename, bkslashes_with_dotW, 4)) + { + static const WCHAR pipeW[] = {'P','I','P','E','\\',0}; + if(!strncmpiW(filename + 4, pipeW, 5)) { - TRACE("Opening a pipe: %s\n",filename); + TRACE("Opening a pipe: %s\n", debugstr_w(filename)); ret = FILE_OpenPipe(filename,access); goto done; } - else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0') + else if (isalphaW(filename[4]) && filename[5] == ':' && filename[6] == '\0') { - ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa ); + ret = FILE_CreateDevice( (toupperW(filename[4]) - 'A') | 0x20000, access, sa ); goto done; } else if (!DOSFS_GetDevice( filename )) @@ -594,23 +612,23 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, } /* If the name still starts with '\\', it's a UNC name. */ - if (!strncmp(filename, "\\\\", 2)) + if (!strncmpW(filename, bkslashesW, 2)) { - ret = SMB_CreateFileA(filename, access, sharing, sa, creation, attributes, template ); + ret = SMB_CreateFileW(filename, access, sharing, sa, creation, attributes, template ); goto done; } /* If the name contains a DOS wild card (* or ?), do no create a file */ - if(strchr(filename,'*') || strchr(filename,'?')) + if(strchrW(filename, '*') || strchrW(filename, '?')) return INVALID_HANDLE_VALUE; /* Open a console for CONIN$ or CONOUT$ */ - if (!strcasecmp(filename, "CONIN$")) + if (!strcmpiW(filename, coninW)) { ret = FILE_OpenConsole( FALSE, access, sharing, sa ); goto done; } - if (!strcasecmp(filename, "CONOUT$")) + if (!strcmpiW(filename, conoutW)) { ret = FILE_OpenConsole( TRUE, access, sharing, sa ); goto done; @@ -618,12 +636,12 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, if (DOSFS_GetDevice( filename )) { - TRACE("opening device '%s'\n", filename ); + TRACE("opening device %s\n", debugstr_w(filename) ); if (!(ret = DOSFS_OpenDevice( filename, access, attributes, sa ))) { /* Do not silence this please. It is a critical error. -MM */ - ERR("Couldn't open device '%s'!\n",filename); + ERR("Couldn't open device %s!\n", debugstr_w(filename)); SetLastError( ERROR_FILE_NOT_FOUND ); } goto done; @@ -634,33 +652,48 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, (creation == OPEN_EXISTING) || (creation == TRUNCATE_EXISTING), &full_name )) { - WARN("Unable to get full filename from '%s' (GLE %ld)\n", - filename, GetLastError()); + WARN("Unable to get full filename from %s (GLE %ld)\n", + debugstr_w(filename), GetLastError()); return INVALID_HANDLE_VALUE; } ret = FILE_CreateFile( full_name.long_name, access, sharing, sa, creation, attributes, template, DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY, - GetDriveTypeA( full_name.short_name ) ); + GetDriveTypeW( full_name.short_name ) ); done: if (!ret) ret = INVALID_HANDLE_VALUE; + TRACE("returning %08x\n", ret); return ret; } /************************************************************************* - * CreateFileW (KERNEL32.@) + * CreateFileA (KERNEL32.@) */ -HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, +HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template) { - LPSTR afn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - HANDLE res = CreateFileA( afn, access, sharing, sa, creation, attributes, template ); - HeapFree( GetProcessHeap(), 0, afn ); - return res; + UNICODE_STRING filenameW; + HANDLE ret = INVALID_HANDLE_VALUE; + + if (!filename) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return INVALID_HANDLE_VALUE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename)) + { + ret = CreateFileW(filenameW.Buffer, access, sharing, sa, creation, + attributes, template); + RtlFreeUnicodeString(&filenameW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return ret; } @@ -735,6 +768,8 @@ DWORD WINAPI GetFileInformationByHandle( HANDLE hFile, DWORD ret; if (!info) return 0; + TRACE("%08x\n", hFile); + SERVER_START_REQ( get_file_info ) { req->handle = hFile; @@ -780,9 +815,9 @@ DWORD WINAPI GetFileAttributes16( LPCSTR name ) /************************************************************************** - * GetFileAttributesA (KERNEL32.@) + * GetFileAttributesW (KERNEL32.@) */ -DWORD WINAPI GetFileAttributesA( LPCSTR name ) +DWORD WINAPI GetFileAttributesW( LPCWSTR name ) { DOS_FULL_NAME full_name; BY_HANDLE_FILE_INFORMATION info; @@ -800,14 +835,27 @@ DWORD WINAPI GetFileAttributesA( LPCSTR name ) /************************************************************************** - * GetFileAttributesW (KERNEL32.@) + * GetFileAttributesA (KERNEL32.@) */ -DWORD WINAPI GetFileAttributesW( LPCWSTR name ) +DWORD WINAPI GetFileAttributesA( LPCSTR name ) { - LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); - DWORD res = GetFileAttributesA( nameA ); - HeapFree( GetProcessHeap(), 0, nameA ); - return res; + UNICODE_STRING nameW; + DWORD ret = (DWORD)-1; + + if (!name) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return (DWORD)-1; + } + + if (RtlCreateUnicodeStringFromAsciiz(&nameW, name)) + { + ret = GetFileAttributesW(nameW.Buffer); + RtlFreeUnicodeString(&nameW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return ret; } @@ -821,17 +869,24 @@ BOOL16 WINAPI SetFileAttributes16( LPCSTR lpFileName, DWORD attributes ) /************************************************************************** - * SetFileAttributesA (KERNEL32.@) + * SetFileAttributesW (KERNEL32.@) */ -BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes) +BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes) { struct stat buf; DOS_FULL_NAME full_name; + if (!lpFileName) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + TRACE("(%s,%lx)\n", debugstr_w(lpFileName), attributes); + if (!DOSFS_GetFullName( lpFileName, TRUE, &full_name )) return FALSE; - TRACE("(%s,%lx)\n",lpFileName,attributes); if(stat(full_name.long_name,&buf)==-1) { FILE_SetDosError(); @@ -854,16 +909,17 @@ BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes) if (attributes & FILE_ATTRIBUTE_DIRECTORY) { if (!S_ISDIR(buf.st_mode)) - FIXME("SetFileAttributes expected the file '%s' to be a directory\n", - lpFileName); + FIXME("SetFileAttributes expected the file %s to be a directory\n", + debugstr_w(lpFileName)); attributes &= ~FILE_ATTRIBUTE_DIRECTORY; } attributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM); if (attributes) - FIXME("(%s):%lx attribute(s) not implemented.\n", lpFileName,attributes); + FIXME("(%s):%lx attribute(s) not implemented.\n", debugstr_w(lpFileName), attributes); if (-1==chmod(full_name.long_name,buf.st_mode)) { - if(GetDriveTypeA(lpFileName) == DRIVE_CDROM) { + if (GetDriveTypeW(lpFileName) == DRIVE_CDROM) + { SetLastError( ERROR_ACCESS_DENIED ); return FALSE; } @@ -886,18 +942,27 @@ BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes) /************************************************************************** - * SetFileAttributesW (KERNEL32.@) + * SetFileAttributesA (KERNEL32.@) */ -BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD attributes) +BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD attributes) { - BOOL res; - DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL ); - LPSTR afn = HeapAlloc( GetProcessHeap(), 0, len ); + UNICODE_STRING filenameW; + HANDLE ret = FALSE; - WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, afn, len, NULL, NULL ); - res = SetFileAttributesA( afn, attributes ); - HeapFree( GetProcessHeap(), 0, afn ); - return res; + if (!lpFileName) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&filenameW, lpFileName)) + { + ret = SetFileAttributesW(filenameW.Buffer, attributes); + RtlFreeUnicodeString(&filenameW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return ret; } @@ -949,30 +1014,36 @@ INT WINAPI CompareFileTime( LPFILETIME x, LPFILETIME y ) /*********************************************************************** * FILE_GetTempFileName : utility for GetTempFileName */ -static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique, - LPSTR buffer, BOOL isWin16 ) +static UINT FILE_GetTempFileName( LPCWSTR path, LPCWSTR prefix, UINT unique, + LPWSTR buffer ) { static UINT unique_temp; DOS_FULL_NAME full_name; int i; - LPSTR p; + LPWSTR p; UINT num; + char buf[20]; - if ( !path || !prefix || !buffer ) return 0; + if ( !path || !prefix || !buffer ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } if (!unique_temp) unique_temp = time(NULL) & 0xffff; num = unique ? (unique & 0xffff) : (unique_temp++ & 0xffff); - strcpy( buffer, path ); - p = buffer + strlen(buffer); + strcpyW( buffer, path ); + p = buffer + strlenW(buffer); /* add a \, if there isn't one and path is more than just the drive letter ... */ - if ( !((strlen(buffer) == 2) && (buffer[1] == ':')) + if ( !((strlenW(buffer) == 2) && (buffer[1] == ':')) && ((p == buffer) || (p[-1] != '\\'))) *p++ = '\\'; - if (isWin16) *p++ = '~'; for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++; - sprintf( p, "%04x.tmp", num ); + + sprintf( buf, "%04x.tmp", num ); + MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20); /* Now try to create it */ @@ -980,19 +1051,19 @@ static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique, { do { - HANDLE handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL, + HANDLE handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); if (handle != INVALID_HANDLE_VALUE) { /* We created it */ - TRACE("created %s\n", - buffer); + TRACE("created %s\n", debugstr_w(buffer) ); CloseHandle( handle ); break; } if (GetLastError() != ERROR_FILE_EXISTS) break; /* No need to go on */ num++; - sprintf( p, "%04x.tmp", num ); + sprintf( buf, "%04x.tmp", num ); + MultiByteToWideChar(CP_ACP, 0, buf, -1, p, 20); } while (num != (unique & 0xffff)); } @@ -1000,13 +1071,14 @@ static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique, if (DOSFS_GetFullName( buffer, FALSE, &full_name )) { + char *slash; /* Check if we have write access in the directory */ - if ((p = strrchr( full_name.long_name, '/' ))) *p = '\0'; + if ((slash = strrchr( full_name.long_name, '/' ))) *slash = '\0'; if (access( full_name.long_name, W_OK ) == -1) - WARN("returns '%s', which doesn't seem to be writeable.\n", - buffer); + WARN("returns %s, which doesn't seem to be writeable.\n", + debugstr_w(buffer) ); } - TRACE("returning %s\n", buffer ); + TRACE("returning %s\n", debugstr_w(buffer) ); return unique ? unique : num; } @@ -1017,7 +1089,26 @@ static UINT FILE_GetTempFileName( LPCSTR path, LPCSTR prefix, UINT unique, UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer) { - return FILE_GetTempFileName(path, prefix, unique, buffer, FALSE); + UNICODE_STRING pathW, prefixW; + WCHAR bufferW[MAX_PATH]; + UINT ret; + + if ( !path || !prefix || !buffer ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + + RtlCreateUnicodeStringFromAsciiz(&pathW, path); + RtlCreateUnicodeStringFromAsciiz(&prefixW, prefix); + + ret = GetTempFileNameW(pathW.Buffer, prefixW.Buffer, unique, bufferW); + if (ret) + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); + + RtlFreeUnicodeString(&pathW); + RtlFreeUnicodeString(&prefixW); + return ret; } /*********************************************************************** @@ -1026,18 +1117,7 @@ UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique, UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR buffer ) { - LPSTR patha,prefixa; - char buffera[144]; - UINT ret; - - if (!path) return 0; - patha = HEAP_strdupWtoA( GetProcessHeap(), 0, path ); - prefixa = HEAP_strdupWtoA( GetProcessHeap(), 0, prefix ); - ret = FILE_GetTempFileName( patha, prefixa, unique, buffera, FALSE ); - MultiByteToWideChar( CP_ACP, 0, buffera, -1, buffer, MAX_PATH ); - HeapFree( GetProcessHeap(), 0, patha ); - HeapFree( GetProcessHeap(), 0, prefixa ); - return ret; + return FILE_GetTempFileName( path, prefix, unique, buffer ); } @@ -1047,7 +1127,9 @@ UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique, LPSTR buffer ) { - char temppath[144]; + char temppath[MAX_PATH]; + char *prefix16 = NULL; + UINT16 ret; if (!(drive & ~TF_FORCEDRIVE)) /* drive 0 means current default drive */ drive |= DRIVE_GetCurrentDrive() + 'A'; @@ -1062,8 +1144,19 @@ UINT16 WINAPI GetTempFileName16( BYTE drive, LPCSTR prefix, UINT16 unique, if (drive & TF_FORCEDRIVE) sprintf(temppath,"%c:", drive & ~TF_FORCEDRIVE ); else - GetTempPathA( 132, temppath ); - return (UINT16)FILE_GetTempFileName( temppath, prefix, unique, buffer, TRUE ); + GetTempPathA( MAX_PATH, temppath ); + + if (prefix) + { + prefix16 = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + 2); + *prefix16 = '~'; + strcpy(prefix16 + 1, prefix); + } + + ret = GetTempFileNameA( temppath, prefix16, unique, buffer ); + + if (prefix16) HeapFree(GetProcessHeap(), 0, prefix16); + return ret; } /*********************************************************************** @@ -1080,7 +1173,9 @@ static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, WORD filedatetime[2]; DOS_FULL_NAME full_name; DWORD access, sharing; - char *p; + WCHAR *p; + WCHAR buffer[MAX_PATH]; + LPWSTR nameW; if (!ofs) return HFILE_ERROR; @@ -1146,28 +1241,31 @@ static HFILE FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode, goto success; } + MultiByteToWideChar(CP_ACP, 0, name, -1, buffer, MAX_PATH); + nameW = buffer; + /* If OF_SEARCH is set, ignore the given path */ if ((mode & OF_SEARCH) && !(mode & OF_REOPEN)) { /* First try the file name as is */ - if (DOSFS_GetFullName( name, TRUE, &full_name )) goto found; + if (DOSFS_GetFullName( nameW, TRUE, &full_name )) goto found; /* Now remove the path */ - if (name[0] && (name[1] == ':')) name += 2; - if ((p = strrchr( name, '\\' ))) name = p + 1; - if ((p = strrchr( name, '/' ))) name = p + 1; - if (!name[0]) goto not_found; + if (nameW[0] && (nameW[1] == ':')) nameW += 2; + if ((p = strrchrW( nameW, '\\' ))) nameW = p + 1; + if ((p = strrchrW( nameW, '/' ))) nameW = p + 1; + if (!nameW[0]) goto not_found; } /* Now look for the file */ - if (!DIR_SearchPath( NULL, name, NULL, &full_name, win32 )) goto not_found; + if (!DIR_SearchPath( NULL, nameW, NULL, &full_name, win32 )) goto not_found; found: TRACE("found %s = %s\n", - full_name.long_name, full_name.short_name ); - lstrcpynA( ofs->szPathName, full_name.short_name, - sizeof(ofs->szPathName) ); + full_name.long_name, debugstr_w(full_name.short_name) ); + WideCharToMultiByte(CP_ACP, 0, full_name.short_name, -1, + ofs->szPathName, sizeof(ofs->szPathName), NULL, NULL); if (mode & OF_SHARE_EXCLUSIVE) /* Some InstallShield version uses OF_SHARE_EXCLUSIVE @@ -1199,9 +1297,9 @@ found: } handle = FILE_CreateFile( full_name.long_name, access, sharing, - NULL, OPEN_EXISTING, 0, 0, - DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY, - GetDriveTypeA( full_name.short_name ) ); + NULL, OPEN_EXISTING, 0, 0, + DRIVE_GetFlags(full_name.drive) & DRIVE_FAIL_READ_ONLY, + GetDriveTypeW( full_name.short_name ) ); if (!handle) goto not_found; GetFileTime( handle, NULL, NULL, &filetime ); @@ -1706,13 +1804,17 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, default: if (unix_handle == -1) return FALSE; - if (overlapped) + } + + if(overlapped) + { + off_t offset = OVERLAPPED_OFFSET(overlapped); + if(lseek(unix_handle, offset, SEEK_SET) == -1) { close(unix_handle); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - break; } /* code for synchronous reads */ @@ -1930,6 +2032,17 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, break; } + if(overlapped) + { + off_t offset = OVERLAPPED_OFFSET(overlapped); + if(lseek(unix_handle, offset, SEEK_SET) == -1) + { + close(unix_handle); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + /* synchronous file write */ while ((result = write( unix_handle, buffer, bytesToWrite )) == -1) { @@ -2224,9 +2337,9 @@ BOOL16 WINAPI DeleteFile16( LPCSTR path ) /*********************************************************************** - * DeleteFileA (KERNEL32.@) + * DeleteFileW (KERNEL32.@) */ -BOOL WINAPI DeleteFileA( LPCSTR path ) +BOOL WINAPI DeleteFileW( LPCWSTR path ) { DOS_FULL_NAME full_name; HANDLE hFile; @@ -2236,7 +2349,7 @@ BOOL WINAPI DeleteFileA( LPCSTR path ) SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - TRACE("'%s'\n", path ); + TRACE("%s\n", debugstr_w(path) ); if (!*path) { @@ -2245,7 +2358,7 @@ BOOL WINAPI DeleteFileA( LPCSTR path ) } if (DOSFS_GetDevice( path )) { - WARN("cannot remove DOS device '%s'!\n", path); + WARN("cannot remove DOS device %s!\n", debugstr_w(path)); SetLastError( ERROR_FILE_NOT_FOUND ); return FALSE; } @@ -2255,7 +2368,7 @@ BOOL WINAPI DeleteFileA( LPCSTR path ) /* check if we are allowed to delete the source */ hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0, TRUE, - GetDriveTypeA( full_name.short_name ) ); + GetDriveTypeW( full_name.short_name ) ); if (!hFile) return FALSE; if (unlink( full_name.long_name ) == -1) @@ -2270,13 +2383,26 @@ BOOL WINAPI DeleteFileA( LPCSTR path ) /*********************************************************************** - * DeleteFileW (KERNEL32.@) + * DeleteFileA (KERNEL32.@) */ -BOOL WINAPI DeleteFileW( LPCWSTR path ) +BOOL WINAPI DeleteFileA( LPCSTR path ) { - LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path ); - BOOL ret = DeleteFileA( xpath ); - HeapFree( GetProcessHeap(), 0, xpath ); + UNICODE_STRING pathW; + BOOL ret = FALSE; + + if (!path) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&pathW, path)) + { + ret = DeleteFileW(pathW.Buffer); + RtlFreeUnicodeString(&pathW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); return ret; } @@ -2339,16 +2465,18 @@ inline static BOOL is_executable( const char *name ) * [0] <- indicates end of strings * */ -static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags ) +static BOOL FILE_AddBootRenameEntry( LPCWSTR fn1, LPCWSTR fn2, DWORD flags ) { - static const char PreString[] = "\\??\\"; - static const char ValueName[] = "PendingFileRenameOperations"; - + static const WCHAR PreString[] = {'\\','?','?','\\',0}; + static const WCHAR ValueName[] = {'P','e','n','d','i','n','g', + 'F','i','l','e','R','e','n','a','m','e', + 'O','p','e','r','a','t','i','o','n','s',0}; BOOL rc = FALSE; HKEY Reboot = 0; - DWORD Type, len1, len2, l; + DWORD Type, len0, len1, len2; DWORD DataSize = 0; BYTE *Buffer = NULL; + WCHAR *p; if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager", &Reboot) != ERROR_SUCCESS) @@ -2358,41 +2486,60 @@ static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD fla return FALSE; } - l = strlen(PreString); - len1 = strlen(fn1) + l + 1; + len0 = strlenW(PreString); + len1 = strlenW(fn1) + len0 + 1; if (fn2) { - len2 = strlen(fn2) + l + 1; + len2 = strlenW(fn2) + len0 + 1; if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */ } - else len2 = 1; /* minimum is the 0 byte for the empty second string */ + else len2 = 1; /* minimum is the 0 characters for the empty second string */ + + /* convert characters to bytes */ + len0 *= sizeof(WCHAR); + len1 *= sizeof(WCHAR); + len2 *= sizeof(WCHAR); /* First we check if the key exists and if so how many bytes it already contains. */ - if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS) + if (RegQueryValueExW(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS) { if (Type != REG_MULTI_SZ) goto Quit; - if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit; - if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS) + if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) ))) goto Quit; + if (RegQueryValueExW(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS) goto Quit; - if (DataSize) DataSize--; /* remove terminating null (will be added back later) */ + if (DataSize) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */ } else { - if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit; + if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + sizeof(WCHAR) ))) goto Quit; DataSize = 0; } - sprintf( Buffer + DataSize, "%s%s", PreString, fn1 ); + + p = (WCHAR *)(Buffer + DataSize); + strcpyW( p, PreString ); + strcatW( p, fn1 ); DataSize += len1; if (fn2) { - sprintf( Buffer + DataSize, "%s%s%s", - (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 ); + p = (WCHAR *)(Buffer + DataSize); + if (flags & MOVEFILE_REPLACE_EXISTING) + *p++ = '!'; + strcpyW( p, PreString ); + strcatW( p, fn2 ); DataSize += len2; } - else Buffer[DataSize++] = 0; + else + { + p = (WCHAR *)(Buffer + DataSize); + *p = 0; + DataSize += sizeof(WCHAR); + } - Buffer[DataSize++] = 0; /* add final null */ - rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize ); + /* add final null */ + p = (WCHAR *)(Buffer + DataSize); + *p = 0; + DataSize += sizeof(WCHAR); + rc = !RegSetValueExW( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize ); Quit: if (Reboot) RegCloseKey(Reboot); @@ -2402,14 +2549,14 @@ static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD fla /************************************************************************** - * MoveFileExA (KERNEL32.@) + * MoveFileExW (KERNEL32.@) */ -BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) +BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag ) { DOS_FULL_NAME full_name1, full_name2; HANDLE hFile; - TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag); + TRACE("(%s,%s,%04lx)\n", debugstr_w(fn1), debugstr_w(fn2), flag); /* FIXME: sparhawk@gmx.at In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED) @@ -2471,15 +2618,15 @@ BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) Perhaps we should queue these command and execute it when exiting... What about using on_exit(2) */ - FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n", - fn1, fn2); + FIXME("Please move existing file %s to file %s when Wine has finished\n", + debugstr_w(fn1), debugstr_w(fn2)); return FILE_AddBootRenameEntry( fn1, fn2, flag ); } - /* check if we are allowed to delete the source */ - hFile = FILE_CreateFile( full_name1.long_name, GENERIC_READ|GENERIC_WRITE, 0, + /* check if we are allowed to rename the source */ + hFile = FILE_CreateFile( full_name1.long_name, 0, 0, NULL, OPEN_EXISTING, 0, 0, TRUE, - GetDriveTypeA( full_name1.short_name ) ); + GetDriveTypeW( full_name1.short_name ) ); if (!hFile) return FALSE; CloseHandle(hFile); @@ -2487,7 +2634,7 @@ BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) ** (but the file not being there is fine) */ hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0, TRUE, - GetDriveTypeA( full_name2.short_name ) ); + GetDriveTypeW( full_name2.short_name ) ); if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE; CloseHandle(hFile); @@ -2500,7 +2647,7 @@ BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) SetLastError( ERROR_FILE_EXISTS ); return FALSE; } - return CopyFileA( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ); + return CopyFileW( fn1, fn2, !(flag & MOVEFILE_REPLACE_EXISTING) ); } if (rename( full_name1.long_name, full_name2.long_name ) == -1) { @@ -2535,7 +2682,7 @@ BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) Perhaps we should queue these command and execute it when exiting... What about using on_exit(2) */ - FIXME("Please delete file '%s' when Wine has finished\n", fn1); + FIXME("Please delete file %s when Wine has finished\n", debugstr_w(fn1)); return FILE_AddBootRenameEntry( fn1, NULL, flag ); } @@ -2549,30 +2696,48 @@ BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) } /************************************************************************** - * MoveFileExW (KERNEL32.@) + * MoveFileExA (KERNEL32.@) */ -BOOL WINAPI MoveFileExW( LPCWSTR fn1, LPCWSTR fn2, DWORD flag ) +BOOL WINAPI MoveFileExA( LPCSTR fn1, LPCSTR fn2, DWORD flag ) { - LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 ); - LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 ); - BOOL res = MoveFileExA( afn1, afn2, flag ); - HeapFree( GetProcessHeap(), 0, afn1 ); - HeapFree( GetProcessHeap(), 0, afn2 ); - return res; + UNICODE_STRING fn1W, fn2W; + BOOL ret; + + if (!fn1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1); + if (fn2) RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2); + else fn2W.Buffer = NULL; + + ret = MoveFileExW( fn1W.Buffer, fn2W.Buffer, flag ); + + RtlFreeUnicodeString(&fn1W); + RtlFreeUnicodeString(&fn2W); + return ret; } /************************************************************************** - * MoveFileA (KERNEL32.@) + * MoveFileW (KERNEL32.@) * * Move file or directory */ -BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 ) +BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 ) { DOS_FULL_NAME full_name1, full_name2; struct stat fstat; - TRACE("(%s,%s)\n", fn1, fn2 ); + if (!fn1 || !fn2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + TRACE("(%s,%s)\n", debugstr_w(fn1), debugstr_w(fn2) ); if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE; if (DOSFS_GetFullName( fn2, TRUE, &full_name2 )) { @@ -2583,7 +2748,7 @@ BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 ) if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE; if (full_name1.drive == full_name2.drive) /* move */ - return MoveFileExA( fn1, fn2, MOVEFILE_COPY_ALLOWED ); + return MoveFileExW( fn1, fn2, MOVEFILE_COPY_ALLOWED ); /* copy */ if (stat( full_name1.long_name, &fstat )) @@ -2599,57 +2764,81 @@ BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 ) SetLastError( ERROR_GEN_FAILURE ); return FALSE; } - return CopyFileA(fn1, fn2, TRUE); /*fail, if exist */ + return CopyFileW(fn1, fn2, TRUE); /*fail, if exist */ } /************************************************************************** - * MoveFileW (KERNEL32.@) + * MoveFileA (KERNEL32.@) */ -BOOL WINAPI MoveFileW( LPCWSTR fn1, LPCWSTR fn2 ) +BOOL WINAPI MoveFileA( LPCSTR fn1, LPCSTR fn2 ) { - LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 ); - LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 ); - BOOL res = MoveFileA( afn1, afn2 ); - HeapFree( GetProcessHeap(), 0, afn1 ); - HeapFree( GetProcessHeap(), 0, afn2 ); - return res; + UNICODE_STRING fn1W, fn2W; + BOOL ret; + + if (!fn1 || !fn2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + RtlCreateUnicodeStringFromAsciiz(&fn1W, fn1); + RtlCreateUnicodeStringFromAsciiz(&fn2W, fn2); + + ret = MoveFileW( fn1W.Buffer, fn2W.Buffer ); + + RtlFreeUnicodeString(&fn1W); + RtlFreeUnicodeString(&fn2W); + return ret; } /************************************************************************** - * CopyFileA (KERNEL32.@) + * CopyFileW (KERNEL32.@) */ -BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists ) +BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists ) { HANDLE h1, h2; BY_HANDLE_FILE_INFORMATION info; DWORD count; BOOL ret = FALSE; - int mode; char buffer[2048]; - if ((h1 = CreateFileA( source, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE) + if (!source || !dest) + { + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; + } + + TRACE("%s -> %s\n", debugstr_w(source), debugstr_w(dest)); + + if ((h1 = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) + { + WARN("Unable to open source %s\n", debugstr_w(source)); + return FALSE; + } + if (!GetFileInformationByHandle( h1, &info )) { + WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source)); CloseHandle( h1 ); return FALSE; } - mode = (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666; - if ((h2 = CreateFileA( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + + if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, fail_if_exists ? CREATE_NEW : CREATE_ALWAYS, info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE) { + WARN("Unable to open dest %s\n", debugstr_w(dest)); CloseHandle( h1 ); return FALSE; } - while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count > 0) + while (ReadFile( h1, buffer, sizeof(buffer), &count, NULL ) && count) { char *p = buffer; - while (count > 0) + while (count != 0) { DWORD res; if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done; @@ -2666,69 +2855,71 @@ done: /************************************************************************** - * CopyFileW (KERNEL32.@) + * CopyFileA (KERNEL32.@) */ -BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists) +BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists) { - LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, source ); - LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, dest ); - BOOL ret = CopyFileA( sourceA, destA, fail_if_exists ); - HeapFree( GetProcessHeap(), 0, sourceA ); - HeapFree( GetProcessHeap(), 0, destA ); + UNICODE_STRING sourceW, destW; + BOOL ret; + + if (!source || !dest) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + RtlCreateUnicodeStringFromAsciiz(&sourceW, source); + RtlCreateUnicodeStringFromAsciiz(&destW, dest); + + ret = CopyFileW(sourceW.Buffer, destW.Buffer, fail_if_exists); + + RtlFreeUnicodeString(&sourceW); + RtlFreeUnicodeString(&destW); return ret; } /************************************************************************** - * CopyFileExA (KERNEL32.@) + * CopyFileExW (KERNEL32.@) * * This implementation ignores most of the extra parameters passed-in into * the "ex" version of the method and calls the CopyFile method. * It will have to be fixed eventually. */ -BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, - LPCSTR destFilename, - LPPROGRESS_ROUTINE progressRoutine, - LPVOID appData, - LPBOOL cancelFlagPointer, - DWORD copyFlags) +BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, LPCWSTR destFilename, + LPPROGRESS_ROUTINE progressRoutine, LPVOID appData, + LPBOOL cancelFlagPointer, DWORD copyFlags) { - BOOL failIfExists = FALSE; - - /* - * Interpret the only flag that CopyFile can interpret. - */ - if ( (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0) - { - failIfExists = TRUE; - } - - return CopyFileA(sourceFilename, destFilename, failIfExists); + /* + * Interpret the only flag that CopyFile can interpret. + */ + return CopyFileW(sourceFilename, destFilename, (copyFlags & COPY_FILE_FAIL_IF_EXISTS) != 0); } /************************************************************************** - * CopyFileExW (KERNEL32.@) + * CopyFileExA (KERNEL32.@) */ -BOOL WINAPI CopyFileExW(LPCWSTR sourceFilename, - LPCWSTR destFilename, - LPPROGRESS_ROUTINE progressRoutine, - LPVOID appData, - LPBOOL cancelFlagPointer, - DWORD copyFlags) +BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename, + LPPROGRESS_ROUTINE progressRoutine, LPVOID appData, + LPBOOL cancelFlagPointer, DWORD copyFlags) { - LPSTR sourceA = HEAP_strdupWtoA( GetProcessHeap(), 0, sourceFilename ); - LPSTR destA = HEAP_strdupWtoA( GetProcessHeap(), 0, destFilename ); + UNICODE_STRING sourceW, destW; + BOOL ret; - BOOL ret = CopyFileExA(sourceA, - destA, - progressRoutine, - appData, - cancelFlagPointer, - copyFlags); + if (!sourceFilename || !destFilename) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - HeapFree( GetProcessHeap(), 0, sourceA ); - HeapFree( GetProcessHeap(), 0, destA ); + RtlCreateUnicodeStringFromAsciiz(&sourceW, sourceFilename); + RtlCreateUnicodeStringFromAsciiz(&destW, destFilename); + ret = CopyFileExW(sourceW.Buffer, destW.Buffer, progressRoutine, appData, + cancelFlagPointer, copyFlags); + + RtlFreeUnicodeString(&sourceW); + RtlFreeUnicodeString(&destW); return ret; } @@ -3058,17 +3249,20 @@ BOOL WINAPI UnlockFile( #endif /************************************************************************** - * GetFileAttributesExA [KERNEL32.@] + * GetFileAttributesExW (KERNEL32.@) */ -BOOL WINAPI GetFileAttributesExA( - LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, +BOOL WINAPI GetFileAttributesExW( + LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation) { DOS_FULL_NAME full_name; BY_HANDLE_FILE_INFORMATION info; - if (lpFileName == NULL) return FALSE; - if (lpFileInformation == NULL) return FALSE; + if (!lpFileName || !lpFileInformation) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } if (fInfoLevelId == GetFileExInfoStandard) { LPWIN32_FILE_ATTRIBUTE_DATA lpFad = @@ -3093,15 +3287,27 @@ BOOL WINAPI GetFileAttributesExA( /************************************************************************** - * GetFileAttributesExW [KERNEL32.@] + * GetFileAttributesExA (KERNEL32.@) */ -BOOL WINAPI GetFileAttributesExW( - LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, +BOOL WINAPI GetFileAttributesExA( + LPCSTR filename, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation) { - LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName ); - BOOL res = - GetFileAttributesExA( nameA, fInfoLevelId, lpFileInformation); - HeapFree( GetProcessHeap(), 0, nameA ); - return res; + UNICODE_STRING filenameW; + BOOL ret = FALSE; + + if (!filename || !lpFileInformation) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (RtlCreateUnicodeStringFromAsciiz(&filenameW, filename)) + { + ret = GetFileAttributesExW(filenameW.Buffer, fInfoLevelId, lpFileInformation); + RtlFreeUnicodeString(&filenameW); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return ret; } diff --git a/files/profile.c b/files/profile.c index 8f342a26adf..2580cf4b8f4 100644 --- a/files/profile.c +++ b/files/profile.c @@ -40,10 +40,13 @@ #include "winbase.h" #include "winnls.h" #include "winerror.h" +#include "ntddk.h" #include "wine/winbase16.h" #include "winreg.h" +#include "drive.h" #include "file.h" #include "heap.h" +#include "wine/unicode.h" #include "wine/server.h" #include "wine/library.h" #include "wine/debug.h" @@ -52,16 +55,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(profile); typedef struct tagPROFILEKEY { - char *value; + WCHAR *value; struct tagPROFILEKEY *next; - char name[1]; + WCHAR name[1]; } PROFILEKEY; typedef struct tagPROFILESECTION { struct tagPROFILEKEY *key; struct tagPROFILESECTION *next; - char name[1]; + WCHAR name[1]; } PROFILESECTION; @@ -69,9 +72,9 @@ typedef struct { BOOL changed; PROFILESECTION *section; - char *dos_name; + WCHAR *dos_name; char *unix_name; - char *filename; + WCHAR *filename; time_t mtime; } PROFILE; @@ -109,23 +112,23 @@ static const char hex[16] = "0123456789ABCDEF"; * Copy the content of an entry into a buffer, removing quotes, and possibly * translating environment variables. */ -static void PROFILE_CopyEntry( char *buffer, const char *value, int len, - int handle_env ) +static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len, + int handle_env, BOOL strip_quote ) { - char quote = '\0'; - const char *p; + WCHAR quote = '\0'; + LPCWSTR p; if(!buffer) return; - if ((*value == '\'') || (*value == '\"')) + if (strip_quote && ((*value == '\'') || (*value == '\"'))) { - if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++; + if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++; } if (!handle_env) { - lstrcpynA( buffer, value, len ); - if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0'; + lstrcpynW( buffer, value, len ); + if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0'; return; } @@ -133,18 +136,19 @@ static void PROFILE_CopyEntry( char *buffer, const char *value, int len, { if ((*p == '$') && (p[1] == '{')) { - char env_val[1024]; - const char *env_p; - const char *p2 = strchr( p, '}' ); + WCHAR env_val[1024]; + LPCWSTR p2 = strchrW( p, '}' ); + int copy_len; if (!p2) continue; /* ignore it */ - lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 )); - if ((env_p = getenv( env_val )) != NULL) + copy_len = min( 1024, (int)(p2-p)-1 ); + strncpyW(env_val, p + 2, copy_len ); + env_val[copy_len - 1] = 0; /* ensure 0 termination */ + *buffer = 0; + if (GetEnvironmentVariableW( env_val, buffer, len)) { - int buffer_len; - lstrcpynA( buffer, env_p, len ); - buffer_len = strlen( buffer ); - buffer += buffer_len; - len -= buffer_len; + copy_len = strlenW( buffer ); + buffer += copy_len; + len -= copy_len; } p = p2 + 1; } @@ -162,14 +166,24 @@ static void PROFILE_CopyEntry( char *buffer, const char *value, int len, static void PROFILE_Save( FILE *file, PROFILESECTION *section ) { PROFILEKEY *key; + char buffer[PROFILE_MAX_LINE_LEN]; for ( ; section; section = section->next) { - if (section->name[0]) fprintf( file, "\r\n[%s]\r\n", section->name ); + if (section->name[0]) + { + WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL); + fprintf( file, "\r\n[%s]\r\n", buffer ); + } for (key = section->key; key; key = key->next) { - fprintf( file, "%s", key->name ); - if (key->value) fprintf( file, "=%s", key->value ); + WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL); + fprintf( file, "%s", buffer ); + if (key->value) + { + WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL); + fprintf( file, "=%s", buffer ); + } fprintf( file, "\r\n" ); } } @@ -217,7 +231,7 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) { char buffer[PROFILE_MAX_LINE_LEN]; char *p, *p2; - int line = 0; + int line = 0, len; PROFILESECTION *section, *first_section; PROFILESECTION **next_section; PROFILEKEY *key, *prev_key, **next_key; @@ -247,9 +261,10 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) { *p2 = '\0'; p++; - if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + strlen(p) ))) + len = strlen(p); + if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) ))) break; - strcpy( section->name, p ); + MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1); section->key = NULL; section->next = NULL; *next_section = section; @@ -257,7 +272,7 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) next_key = §ion->key; prev_key = NULL; - TRACE("New section: '%s'\n",section->name); + TRACE("New section: %s\n", debugstr_w(section->name)); continue; } @@ -276,12 +291,14 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) if(*p || !prev_key || *prev_key->name) { - if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + strlen(p) ))) break; - strcpy( key->name, p ); + len = strlen(p); + if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break; + MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1); if (p2) { - key->value = HeapAlloc( GetProcessHeap(), 0, strlen(p2)+1 ); - strcpy( key->value, p2 ); + len = strlen(p2) + 1; + key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len); } else key->value = NULL; @@ -290,7 +307,8 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) next_key = &key->next; prev_key = key; - TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)"); + TRACE("New key: name=%s, value=%s\n", + debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)"); } } return first_section; @@ -380,11 +398,11 @@ static void convert_config( FILE *in, const char *output_name ) * * Delete a section from a profile tree. */ -static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name ) +static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name ) { while (*section) { - if ((*section)->name[0] && !strcasecmp( (*section)->name, name )) + if ((*section)->name[0] && !strcmpiW( (*section)->name, name )) { PROFILESECTION *to_del = *section; *section = to_del->next; @@ -404,16 +422,16 @@ static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name ) * Delete a key from a profile tree. */ static BOOL PROFILE_DeleteKey( PROFILESECTION **section, - LPCSTR section_name, LPCSTR key_name ) + LPCWSTR section_name, LPCWSTR key_name ) { while (*section) { - if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name )) + if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name )) { PROFILEKEY **key = &(*section)->key; while (*key) { - if (!strcasecmp( (*key)->name, key_name )) + if (!strcmpiW( (*key)->name, key_name )) { PROFILEKEY *to_del = *key; *key = to_del->next; @@ -435,12 +453,12 @@ static BOOL PROFILE_DeleteKey( PROFILESECTION **section, * * Delete all keys from a profile tree. */ -void PROFILE_DeleteAllKeys( LPCSTR section_name) +void PROFILE_DeleteAllKeys( LPCWSTR section_name) { PROFILESECTION **section= &CurProfile->section; while (*section) { - if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name )) + if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name )) { PROFILEKEY **key = &(*section)->key; while (*key) @@ -462,26 +480,26 @@ void PROFILE_DeleteAllKeys( LPCSTR section_name) * * Find a key in a profile tree, optionally creating it. */ -static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, const char *section_name, - const char *key_name, BOOL create, BOOL create_always ) +static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name, + LPCWSTR key_name, BOOL create, BOOL create_always ) { - const char *p; + LPCWSTR p; int seclen, keylen; while (PROFILE_isspace(*section_name)) section_name++; - p = section_name + strlen(section_name) - 1; + p = section_name + strlenW(section_name) - 1; while ((p > section_name) && PROFILE_isspace(*p)) p--; seclen = p - section_name + 1; while (PROFILE_isspace(*key_name)) key_name++; - p = key_name + strlen(key_name) - 1; + p = key_name + strlenW(key_name) - 1; while ((p > key_name) && PROFILE_isspace(*p)) p--; keylen = p - key_name + 1; while (*section) { if ( ((*section)->name[0]) - && (!(strncasecmp( (*section)->name, section_name, seclen ))) + && (!(strncmpiW( (*section)->name, section_name, seclen ))) && (((*section)->name)[seclen] == '\0') ) { PROFILEKEY **key = &(*section)->key; @@ -494,16 +512,16 @@ static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, const char *section_n */ if(!create_always) { - if ( (!(strncasecmp( (*key)->name, key_name, keylen ))) + if ( (!(strncmpiW( (*key)->name, key_name, keylen ))) && (((*key)->name)[keylen] == '\0') ) return *key; } key = &(*key)->next; } if (!create) return NULL; - if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) ))) + if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) ))) return NULL; - strcpy( (*key)->name, key_name ); + strcpyW( (*key)->name, key_name ); (*key)->value = NULL; (*key)->next = NULL; return *key; @@ -511,17 +529,17 @@ static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, const char *section_n section = &(*section)->next; } if (!create) return NULL; - *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlen(section_name) ); + *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) ); if(*section == NULL) return NULL; - strcpy( (*section)->name, section_name ); + strcpyW( (*section)->name, section_name ); (*section)->next = NULL; if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0, - sizeof(PROFILEKEY) + strlen(key_name) ))) + sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) ))) { HeapFree(GetProcessHeap(), 0, *section); return NULL; } - strcpy( (*section)->key->name, key_name ); + strcpyW( (*section)->key->name, key_name ); (*section)->key->value = NULL; (*section)->key->next = NULL; return (*section)->key; @@ -549,24 +567,28 @@ static BOOL PROFILE_FlushFile(void) if (!CurProfile->changed || !CurProfile->dos_name) return TRUE; if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w"))) { + int drive = toupperW(CurProfile->dos_name[0]) - 'A'; + WCHAR *name; /* Try to create it in $HOME/.wine */ /* FIXME: this will need a more general solution */ strcpy( buffer, wine_get_config_dir() ); p = buffer + strlen(buffer); *p++ = '/'; - strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 ); - _strlwr( p ); + *p = 0; /* make strlen() below happy */ + name = strrchrW( CurProfile->dos_name, '\\' ) + 1; + WideCharToMultiByte(DRIVE_GetCodepage(drive), 0, name, -1, + p, sizeof(buffer) - strlen(buffer), NULL, NULL); file = fopen( buffer, "w" ); unix_name = buffer; } if (!file) { - WARN("could not save profile file %s\n", CurProfile->dos_name); + WARN("could not save profile file %s\n", debugstr_w(CurProfile->dos_name)); return FALSE; } - TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name ); + TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name ); PROFILE_Save( file, CurProfile->section ); fclose( file ); CurProfile->changed = FALSE; @@ -602,11 +624,13 @@ static void PROFILE_ReleaseFile(void) * * Open a profile file, checking the cached file first. */ -static BOOL PROFILE_Open( LPCSTR filename ) +static BOOL PROFILE_Open( LPCWSTR filename ) { DOS_FULL_NAME full_name; char buffer[MAX_PATHNAME_LEN]; - char *newdos_name, *p; + WCHAR *newdos_name; + WCHAR *name; + char *p; FILE *file = NULL; int i,j; struct stat buf; @@ -629,23 +653,26 @@ static BOOL PROFILE_Open( LPCSTR filename ) /* Check for a match */ - if (strchr( filename, '/' ) || strchr( filename, '\\' ) || - strchr( filename, ':' )) + if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) || + strchrW( filename, ':' )) { if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE; } else { - GetWindowsDirectoryA( buffer, sizeof(buffer) ); - strcat( buffer, "\\" ); - strcat( buffer, filename ); - if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE; + static const WCHAR bkslashW[] = {'\\',0}; + WCHAR windirW[MAX_PATH]; + + GetWindowsDirectoryW( windirW, MAX_PATH ); + strcatW( windirW, bkslashW ); + strcatW( windirW, filename ); + if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE; } for(i=0;ifilename && !strcmp( filename, MRUProfile[i]->filename )) || - (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name ))) + if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) || + (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name ))) { if(i) { @@ -657,10 +684,10 @@ static BOOL PROFILE_Open( LPCSTR filename ) } if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime) TRACE("(%s): already opened (mru=%d)\n", - filename, i ); + debugstr_w(filename), i ); else TRACE("(%s): already opened, needs refreshing (mru=%d)\n", - filename, i ); + debugstr_w(filename), i ); return TRUE; } } @@ -679,11 +706,11 @@ static BOOL PROFILE_Open( LPCSTR filename ) if(CurProfile->filename) PROFILE_ReleaseFile(); /* OK, now that CurProfile is definitely free we assign it our new file */ - newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 ); - strcpy( newdos_name, full_name.short_name ); + newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) ); + strcpyW( newdos_name, full_name.short_name ); CurProfile->dos_name = newdos_name; - CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, strlen(filename)+1 ); - strcpy( CurProfile->filename, filename ); + CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) ); + strcpyW( CurProfile->filename, filename ); /* Try to open the profile file, first in $HOME/.wine */ @@ -691,23 +718,23 @@ static BOOL PROFILE_Open( LPCSTR filename ) strcpy( buffer, wine_get_config_dir() ); p = buffer + strlen(buffer); *p++ = '/'; - strcpy( p, strrchr( newdos_name, '\\' ) + 1 ); - _strlwr( p ); + *p = 0; /* make strlen() below happy */ + name = strrchrW( newdos_name, '\\' ) + 1; + WideCharToMultiByte(DRIVE_GetCodepage(full_name.drive), 0, name, -1, + p, sizeof(buffer) - strlen(buffer), NULL, NULL); if ((file = fopen( buffer, "r" ))) { - TRACE("(%s): found it in %s\n", - filename, buffer ); + TRACE("(%s): found it in %s\n", debugstr_w(filename), buffer ); CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 ); strcpy( CurProfile->unix_name, buffer ); } - - if (!file) + else { CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); strcpy( CurProfile->unix_name, full_name.long_name ); if ((file = fopen( full_name.long_name, "r" ))) TRACE("(%s): found it in %s\n", - filename, full_name.long_name ); + debugstr_w(filename), full_name.long_name ); } if (file) @@ -720,7 +747,7 @@ static BOOL PROFILE_Open( LPCSTR filename ) else { /* Does not exist yet, we will create it in PROFILE_FlushFile */ - WARN("profile file %s not found\n", newdos_name ); + WARN("profile file %s not found\n", debugstr_w(newdos_name) ); } return TRUE; } @@ -732,17 +759,19 @@ static BOOL PROFILE_Open( LPCSTR filename ) * Returns all keys of a section. * If return_values is TRUE, also include the corresponding values. */ -static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name, - LPSTR buffer, UINT len, BOOL handle_env, +static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name, + LPWSTR buffer, UINT len, BOOL handle_env, BOOL return_values ) { PROFILEKEY *key; if(!buffer) return 0; + TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len); + while (section) { - if (section->name[0] && !strcasecmp( section->name, section_name )) + if (section->name[0] && !strcmpiW( section->name, section_name )) { UINT oldlen = len; for (key = section->key; key; key = key->next) @@ -750,17 +779,17 @@ static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name, if (len <= 2) break; if (!*key->name) continue; /* Skip empty lines */ if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */ - PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env ); - len -= strlen(buffer) + 1; - buffer += strlen(buffer) + 1; + PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env, 0 ); + len -= strlenW(buffer) + 1; + buffer += strlenW(buffer) + 1; if (len < 2) break; if (return_values && key->value) { buffer[-1] = '='; PROFILE_CopyEntry ( buffer, - key->value, len - 1, handle_env ); - len -= strlen(buffer) + 1; - buffer += strlen(buffer) + 1; + key->value, len - 1, handle_env, 0 ); + len -= strlenW(buffer) + 1; + buffer += strlenW(buffer) + 1; } } *buffer = '\0'; @@ -783,9 +812,9 @@ static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name, } /* See GetPrivateProfileSectionNamesA for documentation */ -static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len ) +static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len ) { - LPSTR buf; + LPWSTR buf; UINT f,l; PROFILESECTION *section; @@ -801,17 +830,17 @@ static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len ) section = CurProfile->section; while ((section!=NULL)) { if (section->name[0]) { - l = strlen(section->name)+1; + l = strlenW(section->name)+1; if (l > f) { if (f>0) { - strncpy(buf, section->name, f-1); + strncpyW(buf, section->name, f-1); buf += f-1; *buf++='\0'; } *buf='\0'; return len-2; } - strcpy(buf, section->name); + strcpyW(buf, section->name); buf += l; f -= l; } @@ -844,25 +873,29 @@ static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len ) * * */ -static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name, - LPCSTR def_val, LPSTR buffer, UINT len ) +static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name, + LPCWSTR def_val, LPWSTR buffer, UINT len ) { PROFILEKEY *key = NULL; + static const WCHAR empty_strW[] = { 0 }; if(!buffer) return 0; - if (!def_val) def_val = ""; + if (!def_val) def_val = empty_strW; if (key_name) { if (!key_name[0]) + { /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */ return 0; + } key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE); PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val, - len, FALSE ); - TRACE("('%s','%s','%s'): returning '%s'\n", - section, key_name, def_val, buffer ); - return strlen( buffer ); + len, FALSE, TRUE ); + TRACE("(%s,%s,%s): returning %s\n", + debugstr_w(section), debugstr_w(key_name), + debugstr_w(def_val), debugstr_w(buffer) ); + return strlenW( buffer ); } /* no "else" here ! */ if (section && section[0]) @@ -870,8 +903,8 @@ static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name, INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE); if (!buffer[0]) /* no luck -> def_val */ { - PROFILE_CopyEntry(buffer, def_val, len, FALSE); - ret = strlen(buffer); + PROFILE_CopyEntry(buffer, def_val, len, FALSE, TRUE); + ret = strlenW(buffer); } return ret; } @@ -885,12 +918,12 @@ static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name, * * Set a profile string. */ -static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name, - LPCSTR value, BOOL create_always ) +static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name, + LPCWSTR value, BOOL create_always ) { if (!key_name) /* Delete a whole section */ { - TRACE("('%s')\n", section_name); + TRACE("(%s)\n", debugstr_w(section_name)); CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section, section_name ); return TRUE; /* Even if PROFILE_DeleteSection() has failed, @@ -898,8 +931,7 @@ static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name, } else if (!value) /* Delete a key */ { - TRACE("('%s','%s')\n", - section_name, key_name ); + TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) ); CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section, section_name, key_name ); return TRUE; /* same error handling as above */ @@ -908,8 +940,8 @@ static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name, { PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name, key_name, TRUE, create_always ); - TRACE("('%s','%s','%s'): \n", - section_name, key_name, value ); + TRACE("(%s,%s,%s):\n", + debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) ); if (!key) return FALSE; if (key->value) { @@ -917,17 +949,17 @@ static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name, * friends too, they should not happen here anyway. */ while (PROFILE_isspace(*value)) value++; - if (!strcmp( key->value, value )) + if (!strcmpW( key->value, value )) { TRACE(" no change needed\n" ); return TRUE; /* No change needed */ } - TRACE(" replacing '%s'\n", key->value ); + TRACE(" replacing %s\n", debugstr_w(key->value) ); HeapFree( GetProcessHeap(), 0, key->value ); } else TRACE(" creating key\n" ); - key->value = HeapAlloc( GetProcessHeap(), 0, strlen(value)+1 ); - strcpy( key->value, value ); + key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) ); + strcpyW( key->value, value ); CurProfile->changed = TRUE; } return TRUE; @@ -939,32 +971,31 @@ static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name, * * Get a config string from the wine.ini file. */ -int PROFILE_GetWineIniString( const char *section, const char *key_name, - const char *def, char *buffer, int len ) +int PROFILE_GetWineIniString( LPCWSTR section, LPCWSTR key_name, + LPCWSTR def, LPWSTR buffer, int len ) { - char tmp[PROFILE_MAX_LINE_LEN]; + WCHAR tmp[PROFILE_MAX_LINE_LEN]; HKEY hkey; DWORD err; - if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey ))) + if (!(err = RegOpenKeyW( wine_profile_key, section, &hkey ))) { DWORD type; DWORD count = sizeof(tmp); - err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count ); + err = RegQueryValueExW( hkey, key_name, 0, &type, (LPBYTE)tmp, &count ); RegCloseKey( hkey ); } - PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE ); - TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer ); - return strlen(buffer); + + PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE, TRUE ); + TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section), + debugstr_w(key_name), debugstr_w(def), debugstr_w(buffer) ); + return strlenW(buffer); } /****************************************************************************** * - * int PROFILE_GetWineIniBool( - * char const *section, - * char const *key_name, - * int def ) + * PROFILE_GetWineIniBool * * Reads a boolean value from the wine.ini file. This function attempts to * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0' @@ -975,15 +1006,13 @@ int PROFILE_GetWineIniString( const char *section, const char *key_name, * for existence by setting def to something other than 0 or 1 and * examining the return value. */ -int PROFILE_GetWineIniBool( - char const *section, - char const *key_name, - int def ) +int PROFILE_GetWineIniBool( LPCWSTR section, LPCWSTR key_name, int def ) { - char key_value[2]; + static const WCHAR def_valueW[] = {'~',0}; + WCHAR key_value[2]; int retval; - PROFILE_GetWineIniString(section, key_name, "~", key_value, 2); + PROFILE_GetWineIniString(section, key_name, def_valueW, key_value, 2); switch(key_value[0]) { case 'n': @@ -1006,7 +1035,7 @@ int PROFILE_GetWineIniBool( retval = def; } - TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name, + TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section), debugstr_w(key_name), def ? "TRUE" : "FALSE", key_value[0], retval ? "TRUE" : "FALSE"); @@ -1133,21 +1162,24 @@ UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val ) * - of Keys in a Section if 'entry' is NULL * (see MSDN doc for GetPrivateProfileString) */ -static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry, - LPCSTR def_val, LPSTR buffer, - UINT16 len, LPCSTR filename, +static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry, + LPCWSTR def_val, LPWSTR buffer, + UINT len, LPCWSTR filename, BOOL allow_section_name_copy ) { int ret; - LPSTR pDefVal = NULL; + LPWSTR pDefVal = NULL; if (!filename) - filename = "win.ini"; + filename = wininiW; + + TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry), + debugstr_w(def_val), buffer, len, debugstr_w(filename)); /* strip any trailing ' ' of def_val. */ if (def_val) { - LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */ + LPCWSTR p = &def_val[strlenW(def_val)]; /* even "" works ! */ while (p > def_val) { @@ -1157,14 +1189,14 @@ static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry, } if (*p == ' ') /* ouch, contained trailing ' ' */ { - int len = (int)p - (int)def_val; - pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1); - strncpy(pDefVal, def_val, len); + int len = (int)(p - def_val); + pDefVal = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + strncpyW(pDefVal, def_val, len); pDefVal[len] = '\0'; } } if (!pDefVal) - pDefVal = (LPSTR)def_val; + pDefVal = (LPWSTR)def_val; EnterCriticalSection( &PROFILE_CritSect ); @@ -1175,8 +1207,8 @@ static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry, /* PROFILE_GetString already handles the 'entry == NULL' case */ ret = PROFILE_GetString( section, entry, pDefVal, buffer, len ); } else { - lstrcpynA( buffer, pDefVal, len ); - ret = strlen( buffer ); + lstrcpynW( buffer, pDefVal, len ); + ret = strlenW( buffer ); } LeaveCriticalSection( &PROFILE_CritSect ); @@ -1184,6 +1216,8 @@ static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry, if (pDefVal != def_val) /* allocated */ HeapFree(GetProcessHeap(), 0, pDefVal); + TRACE("returning %s, %d\n", debugstr_w(buffer), ret); + return ret; } @@ -1194,8 +1228,41 @@ INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val, LPSTR buffer, UINT16 len, LPCSTR filename ) { - return PROFILE_GetPrivateProfileString( section, entry, def_val, - buffer, len, filename, FALSE ); + UNICODE_STRING sectionW, entryW, def_valW, filenameW; + LPWSTR bufferW; + INT16 retW, ret = 0; + + bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL; + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry); + else entryW.Buffer = NULL; + if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val); + else def_valW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + + retW = PROFILE_GetPrivateProfileString( sectionW.Buffer, entryW.Buffer, + def_valW.Buffer, bufferW, len, + filenameW.Buffer, FALSE ); + if (len) + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL); + if (!ret) + { + ret = len - 1; + buffer[ret] = 0; + } + else + ret--; /* strip terminating 0 */ + } + + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&entryW); + RtlFreeUnicodeString(&def_valW); + RtlFreeUnicodeString(&filenameW); + if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW); + return ret; } /*********************************************************************** @@ -1205,8 +1272,41 @@ INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val, LPSTR buffer, UINT len, LPCSTR filename ) { - return PROFILE_GetPrivateProfileString( section, entry, def_val, - buffer, len, filename, TRUE ); + UNICODE_STRING sectionW, entryW, def_valW, filenameW; + LPWSTR bufferW; + INT retW, ret = 0; + + bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL; + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry); + else entryW.Buffer = NULL; + if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val); + else def_valW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + + retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer, + def_valW.Buffer, bufferW, len, + filenameW.Buffer); + if (len) + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL); + if (!ret) + { + ret = len - 1; + buffer[ret] = 0; + } + else + ret--; /* strip terminating 0 */ + } + + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&entryW); + RtlFreeUnicodeString(&def_valW); + RtlFreeUnicodeString(&filenameW); + if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW); + return ret; } /*********************************************************************** @@ -1216,21 +1316,8 @@ INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, LPCWSTR def_val, LPWSTR buffer, UINT len, LPCWSTR filename ) { - LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); - LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry ); - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val ); - LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len ); - INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA, - bufferA, len, filenameA ); - if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len )) - buffer[len-1] = 0; - HeapFree( GetProcessHeap(), 0, sectionA ); - HeapFree( GetProcessHeap(), 0, entryA ); - HeapFree( GetProcessHeap(), 0, filenameA ); - HeapFree( GetProcessHeap(), 0, def_valA ); - HeapFree( GetProcessHeap(), 0, bufferA); - return ret; + return PROFILE_GetPrivateProfileString( section, entry, def_val, + buffer, len, filename, TRUE ); } /*********************************************************************** @@ -1239,8 +1326,8 @@ INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val, LPSTR buffer, UINT16 len ) { - return PROFILE_GetPrivateProfileString( section, entry, def_val, - buffer, len, "win.ini", FALSE ); + return GetPrivateProfileString16( section, entry, def_val, + buffer, len, "win.ini" ); } /*********************************************************************** @@ -1249,8 +1336,8 @@ INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val, INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val, LPSTR buffer, UINT len ) { - return PROFILE_GetPrivateProfileString( section, entry, def_val, - buffer, len, "win.ini", TRUE ); + return GetPrivateProfileStringA( section, entry, def_val, + buffer, len, "win.ini" ); } /*********************************************************************** @@ -1312,8 +1399,8 @@ UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry, char buffer[20]; long result; - if (!PROFILE_GetPrivateProfileString( section, entry, "", - buffer, sizeof(buffer), filename, FALSE )) + if (!GetPrivateProfileStringA( section, entry, "", + buffer, sizeof(buffer), filename )) return def_val; /* FIXME: if entry can be found but it's empty, then Win16 is * supposed to return 0 instead of def_val ! Difficult/problematic @@ -1331,6 +1418,8 @@ UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry, /*********************************************************************** * GetPrivateProfileIntW (KERNEL32.@) + * + * FIXME: rewrite using unicode */ UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val, LPCWSTR filename ) @@ -1355,10 +1444,10 @@ INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer, } /*********************************************************************** - * GetPrivateProfileSectionA (KERNEL32.@) + * GetPrivateProfileSectionW (KERNEL32.@) */ -INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer, - DWORD len, LPCSTR filename ) +INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer, + DWORD len, LPCWSTR filename ) { int ret = 0; @@ -1374,22 +1463,43 @@ INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer, } /*********************************************************************** - * GetPrivateProfileSectionW (KERNEL32.@) + * GetPrivateProfileSectionA (KERNEL32.@) */ - -INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer, - DWORD len, LPCWSTR filename ) - +INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer, + DWORD len, LPCSTR filename ) { - LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len ); - INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len, - filenameA ); - MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len); - HeapFree( GetProcessHeap(), 0, sectionA ); - HeapFree( GetProcessHeap(), 0, filenameA ); - HeapFree( GetProcessHeap(), 0, bufferA); + UNICODE_STRING sectionW, filenameW; + LPWSTR bufferW; + INT retW, ret = 0; + + bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL; + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + + retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len, filenameW.Buffer); + if (len > 2) + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 2, buffer, len, NULL, NULL); + if (ret > 2) + ret -= 2; + else + { + ret = 0; + buffer[len-2] = 0; + buffer[len-1] = 0; + } + } + else + { + buffer[0] = 0; + buffer[1] = 0; + } + + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&filenameW); + if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW); return ret; } @@ -1428,10 +1538,10 @@ BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry, } /*********************************************************************** - * WritePrivateProfileStringA (KERNEL32.@) + * WritePrivateProfileStringW (KERNEL32.@) */ -BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry, - LPCSTR string, LPCSTR filename ) +BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry, + LPCWSTR string, LPCWSTR filename ) { BOOL ret = FALSE; @@ -1440,12 +1550,17 @@ BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry, if (PROFILE_Open( filename )) { if (!section && !entry && !string) /* documented "file flush" case */ + { + PROFILE_FlushFile(); PROFILE_ReleaseFile(); /* always return FALSE in this case */ + } else { if (!section) { - FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename); + FIXME("(NULL?,%s,%s,%s)?\n", + debugstr_w(entry), debugstr_w(string), debugstr_w(filename)); } else { ret = PROFILE_SetString( section, entry, string, FALSE); + PROFILE_FlushFile(); } } } @@ -1455,22 +1570,30 @@ BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry, } /*********************************************************************** - * WritePrivateProfileStringW (KERNEL32.@) + * WritePrivateProfileStringA (KERNEL32.@) */ -BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry, - LPCWSTR string, LPCWSTR filename ) +BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry, + LPCSTR string, LPCSTR filename ) { - LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); - LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry ); - LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string ); - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - BOOL res = WritePrivateProfileStringA( sectionA, entryA, - stringA, filenameA ); - HeapFree( GetProcessHeap(), 0, sectionA ); - HeapFree( GetProcessHeap(), 0, entryA ); - HeapFree( GetProcessHeap(), 0, stringA ); - HeapFree( GetProcessHeap(), 0, filenameA ); - return res; + UNICODE_STRING sectionW, entryW, stringW, filenameW; + BOOL ret; + + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry); + else entryW.Buffer = NULL; + if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string); + else stringW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + + ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer, + stringW.Buffer, filenameW.Buffer); + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&entryW); + RtlFreeUnicodeString(&stringW); + RtlFreeUnicodeString(&filenameW); + return ret; } /*********************************************************************** @@ -1483,34 +1606,36 @@ BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section, } /*********************************************************************** - * WritePrivateProfileSectionA (KERNEL32.@) + * WritePrivateProfileSectionW (KERNEL32.@) */ -BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section, - LPCSTR string, LPCSTR filename ) +BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section, + LPCWSTR string, LPCWSTR filename ) { BOOL ret = FALSE; - LPSTR p ; + LPWSTR p; EnterCriticalSection( &PROFILE_CritSect ); if (PROFILE_Open( filename )) { if (!section && !string) PROFILE_ReleaseFile(); /* always return FALSE in this case */ - else if (!string) /* delete the named section*/ + else if (!string) {/* delete the named section*/ ret = PROFILE_SetString(section,NULL,NULL, FALSE); - else { + PROFILE_FlushFile(); + } else { PROFILE_DeleteAllKeys(section); ret = TRUE; while(*string) { - LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 ); - strcpy( buf, string ); - if((p=strchr( buf, '='))){ + LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) ); + strcpyW( buf, string ); + if((p = strchrW( buf, '='))) { *p='\0'; ret = PROFILE_SetString( section, buf, p+1, TRUE); } HeapFree( GetProcessHeap(), 0, buf ); - string += strlen(string)+1; + string += strlenW(string)+1; } + PROFILE_FlushFile(); } } @@ -1519,20 +1644,39 @@ BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section, } /*********************************************************************** - * WritePrivateProfileSectionW (KERNEL32.@) + * WritePrivateProfileSectionA (KERNEL32.@) */ -BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section, - LPCWSTR string, LPCWSTR filename) +BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section, + LPCSTR string, LPCSTR filename) { - LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); - LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string ); - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA ); - HeapFree( GetProcessHeap(), 0, sectionA ); - HeapFree( GetProcessHeap(), 0, stringA ); - HeapFree( GetProcessHeap(), 0, filenameA ); - return res; + UNICODE_STRING sectionW, filenameW; + LPWSTR stringW; + BOOL ret; + + if (string) + { + INT lenA, lenW; + LPCSTR p = string; + + while(*p) p += strlen(p) + 1; + lenA = p - string + 1; + lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0); + if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)))) + MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW); + } + else stringW = NULL; + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + + ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer); + + HeapFree(GetProcessHeap(), 0, stringW); + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&filenameW); + return ret; } /*********************************************************************** @@ -1557,7 +1701,7 @@ BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values) */ BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values) { - return (WritePrivateProfileSectionW (section,keys_n_values, wininiW)); + return WritePrivateProfileSectionW(section, keys_n_values, wininiW); } /*********************************************************************** @@ -1581,7 +1725,7 @@ WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size) /*********************************************************************** - * GetPrivateProfileSectionNamesA (KERNEL32.@) + * GetPrivateProfileSectionNamesW (KERNEL32.@) * * Returns the section names contained in the specified file. * FIXME: Where do we find this file when the path is relative? @@ -1617,9 +1761,8 @@ WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size) * Note that when the buffer is big enough then the return value may be any * value between 1 and len-1 (or len in Win95), including len-2. */ -DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size, - LPCSTR filename) - +DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size, + LPCWSTR filename) { DWORD ret = 0; @@ -1635,21 +1778,32 @@ DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size, /*********************************************************************** - * GetPrivateProfileSectionNamesW (KERNEL32.@) + * GetPrivateProfileSectionNamesA (KERNEL32.@) */ -DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size, - LPCWSTR filename) - +DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size, + LPCSTR filename) { - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size); + UNICODE_STRING filenameW; + LPWSTR bufferW; + INT retW, ret = 0; - INT ret = GetPrivateProfileSectionNamesA(bufferA, size, filenameA); - if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size )) - buffer[size-1] = 0; - HeapFree( GetProcessHeap(), 0, bufferA); - HeapFree( GetProcessHeap(), 0, filenameA ); + bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer); + if (retW && size) + { + ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, size, NULL, NULL); + if (!ret) + { + ret = size; + buffer[size-1] = 0; + } + } + + RtlFreeUnicodeString(&filenameW); + if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW); return ret; } @@ -1663,12 +1817,12 @@ BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key, } /*********************************************************************** - * GetPrivateProfileStructA (KERNEL32.@) + * GetPrivateProfileStructW (KERNEL32.@) * * Should match Win95's behaviour pretty much */ -BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, - LPVOID buf, UINT len, LPCSTR filename) +BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key, + LPVOID buf, UINT len, LPCWSTR filename) { BOOL ret = FALSE; @@ -1677,22 +1831,22 @@ BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, if (PROFILE_Open( filename )) { PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE); if (k) { - TRACE("value (at %p): '%s'\n", k->value, k->value); - if (((strlen(k->value) - 2) / 2) == len) + TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value)); + if (((strlenW(k->value) - 2) / 2) == len) { - LPSTR end, p; + LPWSTR end, p; BOOL valid = TRUE; - CHAR c; + WCHAR c; DWORD chksum = 0; - end = k->value + strlen(k->value); /* -> '\0' */ + end = k->value + strlenW(k->value); /* -> '\0' */ /* check for invalid chars in ASCII coded hex string */ for (p=k->value; p < end; p++) { - if (!isxdigit(*p)) + if (!isxdigitW(*p)) { - WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n", - *p, filename, section, key); + WARN("invalid char '%x' in file %s->[%s]->%s !\n", + *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key)); valid = FALSE; break; } @@ -1707,7 +1861,7 @@ BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, /* translate ASCII hex format into binary data */ for (p=k->value; p < end; p++) { - c = toupper(*p); + c = toupperW(*p); val = (c > '9') ? (c - 'A' + 10) : (c - '0'); @@ -1722,9 +1876,9 @@ BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, highnibble ^= 1; /* toggle */ } /* retrieve stored checksum value */ - c = toupper(*p++); + c = toupperW(*p++); b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4; - c = toupper(*p); + c = toupperW(*p); b += (c > '9') ? (c - 'A' + 10) : (c - '0'); if (b == (chksum & 0xff)) /* checksums match ? */ ret = TRUE; @@ -1738,25 +1892,28 @@ BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, } /*********************************************************************** - * GetPrivateProfileStructW (KERNEL32.@) + * GetPrivateProfileStructA (KERNEL32.@) */ -BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key, - LPVOID buffer, UINT len, LPCWSTR filename) +BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, + LPVOID buffer, UINT len, LPCSTR filename) { - LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); - LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key); - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len ); + UNICODE_STRING sectionW, keyW, filenameW; + INT ret; - INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA, - len, filenameA ); - if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len )) - ((LPWSTR)buffer)[len-1] = 0; - HeapFree( GetProcessHeap(), 0, bufferA); - HeapFree( GetProcessHeap(), 0, sectionA ); - HeapFree( GetProcessHeap(), 0, keyA ); - HeapFree( GetProcessHeap(), 0, filenameA ); + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key); + else keyW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len, + filenameW.Buffer); + /* Do not translate binary data. */ + + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&keyW); + RtlFreeUnicodeString(&filenameW); return ret; } @@ -1772,21 +1929,21 @@ BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key, } /*********************************************************************** - * WritePrivateProfileStructA (KERNEL32.@) + * WritePrivateProfileStructW (KERNEL32.@) */ -BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key, - LPVOID buf, UINT bufsize, LPCSTR filename) +BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key, + LPVOID buf, UINT bufsize, LPCWSTR filename) { BOOL ret = FALSE; LPBYTE binbuf; - LPSTR outstring, p; + LPWSTR outstring, p; DWORD sum = 0; if (!section && !key && !buf) /* flush the cache */ - return WritePrivateProfileStringA( NULL, NULL, NULL, filename ); + return WritePrivateProfileStringW( NULL, NULL, NULL, filename ); /* allocate string buffer for hex chars + checksum hex char + '\0' */ - outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1); + outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) ); p = outstring; for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) { *p++ = hex[*binbuf >> 4]; @@ -1800,8 +1957,10 @@ BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key, EnterCriticalSection( &PROFILE_CritSect ); - if (PROFILE_Open( filename )) + if (PROFILE_Open( filename )) { ret = PROFILE_SetString( section, key, outstring, FALSE); + PROFILE_FlushFile(); + } LeaveCriticalSection( &PROFILE_CritSect ); @@ -1811,20 +1970,28 @@ BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key, } /*********************************************************************** - * WritePrivateProfileStructW (KERNEL32.@) + * WritePrivateProfileStructA (KERNEL32.@) */ -BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key, - LPVOID buf, UINT bufsize, LPCWSTR filename) +BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key, + LPVOID buf, UINT bufsize, LPCSTR filename) { - LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); - LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key); - LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); - INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize, - filenameA ); - HeapFree( GetProcessHeap(), 0, sectionA ); - HeapFree( GetProcessHeap(), 0, keyA ); - HeapFree( GetProcessHeap(), 0, filenameA ); + UNICODE_STRING sectionW, keyW, filenameW; + INT ret; + if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); + else sectionW.Buffer = NULL; + if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key); + else keyW.Buffer = NULL; + if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); + else filenameW.Buffer = NULL; + + /* Do not translate binary data. */ + ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize, + filenameW.Buffer); + + RtlFreeUnicodeString(§ionW); + RtlFreeUnicodeString(&keyW); + RtlFreeUnicodeString(&filenameW); return ret; } diff --git a/files/smb.c b/files/smb.c index 9624c5e43cd..d772b809097 100644 --- a/files/smb.c +++ b/files/smb.c @@ -1392,7 +1392,7 @@ static HANDLE SMB_RegisterFile( int fd, USHORT tree_id, USHORT user_id, USHORT d return ret; } -HANDLE WINAPI SMB_CreateFileA( LPCSTR uncname, DWORD access, DWORD sharing, +HANDLE WINAPI SMB_CreateFileW( LPCWSTR uncname, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template ) { @@ -1400,12 +1400,14 @@ HANDLE WINAPI SMB_CreateFileA( LPCSTR uncname, DWORD access, DWORD sharing, USHORT tree_id=0, user_id=0, dialect=0, file_id=0; LPSTR name,host,share,file; HANDLE handle = INVALID_HANDLE_VALUE; + INT len; - name = HeapAlloc(GetProcessHeap(),0,lstrlenA(uncname)); + len = WideCharToMultiByte(CP_ACP, 0, uncname, -1, NULL, 0, NULL, NULL); + name = HeapAlloc(GetProcessHeap(), 0, len); if(!name) return handle; - lstrcpyA(name,uncname); + WideCharToMultiByte(CP_ACP, 0, uncname, -1, name, len, NULL, NULL); if( !UNC_SplitName(name, &host, &share, &file) ) { @@ -1545,21 +1547,22 @@ BOOL WINAPI SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD return r; } -SMB_DIR* WINAPI SMB_FindFirst(LPCSTR name) +SMB_DIR* WINAPI SMB_FindFirst(LPCWSTR name) { int fd = -1; LPSTR host,share,file; USHORT tree_id=0, user_id=0, dialect=0; SMB_DIR *ret = NULL; LPSTR filename; + DWORD len; - TRACE("Find %s\n",debugstr_a(name)); + TRACE("Find %s\n",debugstr_w(name)); - filename = HeapAlloc(GetProcessHeap(),0,lstrlenA(name)+1); + len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL ); + filename = HeapAlloc(GetProcessHeap(),0,len); if(!filename) return ret; - - lstrcpyA(filename,name); + WideCharToMultiByte( CP_ACP, 0, name, -1, filename, len, NULL, NULL ); if( !UNC_SplitName(filename, &host, &share, &file) ) goto done; @@ -1587,7 +1590,7 @@ done: } -BOOL WINAPI SMB_FindNext(SMB_DIR *dir, WIN32_FIND_DATAA *data ) +BOOL WINAPI SMB_FindNext(SMB_DIR *dir, WIN32_FIND_DATAW *data ) { unsigned char *ent; int len, fnlen; @@ -1613,14 +1616,16 @@ BOOL WINAPI SMB_FindNext(SMB_DIR *dir, WIN32_FIND_DATAA *data ) /* copy the long filename */ fnlen = SMB_GETDWORD(&ent[0x3c]); - if ( fnlen > (sizeof data->cFileName/sizeof(CHAR)) ) + if ( fnlen > (sizeof data->cFileName/sizeof(WCHAR)) ) return FALSE; - memcpy(data->cFileName, &ent[0x5e], fnlen); + MultiByteToWideChar( CP_ACP, 0, &ent[0x5e], fnlen, data->cFileName, + sizeof(data->cFileName)/sizeof(WCHAR) ); /* copy the short filename */ - if ( ent[0x44] > (sizeof data->cAlternateFileName/sizeof(CHAR)) ) + if ( ent[0x44] > (sizeof data->cAlternateFileName/sizeof(WCHAR)) ) return FALSE; - memcpy(data->cAlternateFileName, &ent[0x5e + len], ent[0x44]); + MultiByteToWideChar( CP_ACP, 0, &ent[0x5e + len], ent[0x44], data->cAlternateFileName, + sizeof(data->cAlternateFileName)/sizeof(WCHAR) ); dir->current++; diff --git a/files/smb.h b/files/smb.h index 0b2e33036eb..eed17602c02 100644 --- a/files/smb.h +++ b/files/smb.h @@ -96,7 +96,7 @@ #define TRANS2_FIND_NEXT2 0x02 extern BOOL WINAPI SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped); -extern HANDLE WINAPI SMB_CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, +extern HANDLE WINAPI SMB_CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template ); @@ -108,8 +108,8 @@ typedef struct tagSMB_DIR unsigned char *buffer; } SMB_DIR; -extern SMB_DIR* WINAPI SMB_FindFirst(LPCSTR filename); -extern BOOL WINAPI SMB_FindNext(SMB_DIR *dir, WIN32_FIND_DATAA *data ); +extern SMB_DIR* WINAPI SMB_FindFirst(LPCWSTR filename); +extern BOOL WINAPI SMB_FindNext(SMB_DIR *dir, WIN32_FIND_DATAW *data ); extern BOOL WINAPI SMB_CloseDir(SMB_DIR *dir); #endif /* __INC_SMB__ */ diff --git a/include/drive.h b/include/drive.h index c69a599554f..70fe95c5567 100644 --- a/include/drive.h +++ b/include/drive.h @@ -39,15 +39,17 @@ extern int DRIVE_IsValid( int drive ); extern int DRIVE_GetCurrentDrive(void); extern int DRIVE_SetCurrentDrive( int drive ); extern int DRIVE_FindDriveRoot( const char **path ); +extern int DRIVE_FindDriveRootW( LPCWSTR *path ); extern const char * DRIVE_GetRoot( int drive ); -extern const char * DRIVE_GetDosCwd( int drive ); +extern LPCWSTR DRIVE_GetDosCwd( int drive ); extern const char * DRIVE_GetUnixCwd( int drive ); extern const char * DRIVE_GetDevice( int drive ); -extern const char * DRIVE_GetLabel( int drive ); +extern LPCWSTR DRIVE_GetLabel( int drive ); extern DWORD DRIVE_GetSerialNumber( int drive ); extern int DRIVE_SetSerialNumber( int drive, DWORD serial ); extern UINT DRIVE_GetFlags( int drive ); -extern int DRIVE_Chdir( int drive, const char *path ); +extern UINT DRIVE_GetCodepage( int drive ); +extern int DRIVE_Chdir( int drive, LPCWSTR path ); extern int DRIVE_Disable( int drive ); extern int DRIVE_Enable( int drive ); extern int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive ); diff --git a/include/file.h b/include/file.h index cfd35ac226c..51a859883d9 100644 --- a/include/file.h +++ b/include/file.h @@ -26,6 +26,7 @@ #include #include "winbase.h" #include "wine/windef16.h" /* HFILE16 */ +#include "wine/unicode.h" #define MAX_PATHNAME_LEN 1024 @@ -33,7 +34,7 @@ typedef struct { char long_name[MAX_PATHNAME_LEN]; /* Long pathname in Unix format */ - char short_name[MAX_PATHNAME_LEN]; /* Short pathname in DOS 8.3 format */ + WCHAR short_name[MAX_PATHNAME_LEN]; /* Short pathname in DOS 8.3 format */ int drive; } DOS_FULL_NAME; @@ -42,8 +43,9 @@ typedef struct /* DOS device descriptor */ typedef struct { - char *name; + const WCHAR name[9]; int flags; + UINT codepage; } DOS_DEVICE; /* locale-independent case conversion */ @@ -64,6 +66,12 @@ inline static int FILE_contains_path (LPCSTR name) strchr (name, '/') || strchr (name, '\\')); } +inline static int FILE_contains_pathW (LPCWSTR name) +{ + return ((*name && (name[1] == ':')) || + strchrW (name, '/') || strchrW (name, '\\')); +} + /* files/file.c */ extern mode_t FILE_umask; extern int FILE_strcasecmp( const char *str1, const char *str2 ); @@ -86,21 +94,20 @@ extern UINT DIR_GetWindowsUnixDir( LPSTR path, UINT count ); extern UINT DIR_GetSystemUnixDir( LPSTR path, UINT count ); extern DWORD DIR_SearchAlternatePath( LPCSTR dll_path, LPCSTR name, LPCSTR ext, DWORD buflen, LPSTR buffer, LPSTR *lastpart); -extern DWORD DIR_SearchPath( LPCSTR path, LPCSTR name, LPCSTR ext, +extern DWORD DIR_SearchPath( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DOS_FULL_NAME *full_name, BOOL win32 ); /* files/dos_fs.c */ extern void DOSFS_UnixTimeToFileTime( time_t unixtime, LPFILETIME ft, DWORD remainder ); extern time_t DOSFS_FileTimeToUnixTime( const FILETIME *ft, DWORD *remainder ); -extern BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ); -extern const DOS_DEVICE *DOSFS_GetDevice( const char *name ); +extern BOOL DOSFS_ToDosFCBFormat( LPCWSTR name, LPWSTR buffer ); +extern const DOS_DEVICE *DOSFS_GetDevice( LPCWSTR name ); extern const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile ); -extern HANDLE DOSFS_OpenDevice( const char *name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa); -extern BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, - INT long_len, LPSTR short_buf, - BOOL ignore_case ); -extern BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, +extern HANDLE DOSFS_OpenDevice( LPCWSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa); +extern BOOL DOSFS_FindUnixName( const DOS_FULL_NAME *path, LPCWSTR name, char *long_buf, + 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, @@ -109,12 +116,12 @@ extern int DOSFS_FindNext( const char *path, const char *short_mask, /* profile.c */ extern int PROFILE_LoadWineIni(void); extern void PROFILE_UsageWineIni(void); -extern int PROFILE_GetWineIniString( const char *section, const char *key_name, - const char *def, char *buffer, int len ); -extern int PROFILE_GetWineIniBool( char const *section, char const *key_name, int def ); +extern int PROFILE_GetWineIniString( LPCWSTR section, LPCWSTR key_name, + LPCWSTR def, LPWSTR buffer, int len ); +extern int PROFILE_GetWineIniBool( LPCWSTR section, LPCWSTR key_name, int def ); /* win32/device.c */ -extern HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ); +extern HANDLE DEVICE_Open( LPCWSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ); /* ntdll/cdrom.c.c */ extern BOOL CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode, diff --git a/loader/task.c b/loader/task.c index 6a1dfee2edd..f2bd9c75411 100644 --- a/loader/task.c +++ b/loader/task.c @@ -290,8 +290,9 @@ static TDB *TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cm pTask->teb = teb; pTask->curdrive = DRIVE_GetCurrentDrive() | 0x80; strcpy( pTask->curdir, "\\" ); - lstrcpynA( pTask->curdir + 1, DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() ), - sizeof(pTask->curdir) - 1 ); + WideCharToMultiByte(CP_ACP, 0, DRIVE_GetDosCwd(DRIVE_GetCurrentDrive()), -1, + pTask->curdir + 1, sizeof(pTask->curdir) - 1, NULL, NULL); + pTask->curdir[sizeof(pTask->curdir) - 1] = 0; /* ensure 0 termination */ /* Create the thunks block */ diff --git a/memory/registry.c b/memory/registry.c index ed1b5f0a7f5..8280c0f34ef 100644 --- a/memory/registry.c +++ b/memory/registry.c @@ -46,11 +46,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(reg); /* check if value type needs string conversion (Ansi<->Unicode) */ -static inline int is_string( DWORD type ) +inline static int is_string( DWORD type ) { return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ); } +/* check if current version is NT or Win95 */ +inline static int is_version_nt(void) +{ + return !(GetVersion() & 0x80000000); +} /****************************************************************************** * RegCreateKeyExA [ADVAPI32.@] @@ -90,6 +95,27 @@ DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR clas } +/****************************************************************************** + * RegOpenKeyW [ADVAPI32.@] + * + * PARAMS + * hkey [I] Handle of open key + * name [I] Address of name of subkey to open + * retkey [O] Handle to open key + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + * + * NOTES + * in case of failing is retkey = 0 + */ +DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey ) +{ + return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey ); +} + + /****************************************************************************** * RegCreateKeyA [ADVAPI32.@] */ @@ -101,6 +127,43 @@ DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey ) +/****************************************************************************** + * RegOpenKeyExW [ADVAPI32.@] + * + * Opens the specified key + * + * Unlike RegCreateKeyEx, this does not create the key if it does not exist. + * + * PARAMS + * hkey [I] Handle of open key + * name [I] Name of subkey to open + * reserved [I] Reserved - must be zero + * access [I] Security access mask + * retkey [O] Handle to open key + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + * + * NOTES + * in case of failing is retkey = 0 + */ +DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + + attr.Length = sizeof(attr); + attr.RootDirectory = hkey; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &nameW, name ); + return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) ); +} + + /****************************************************************************** * RegOpenKeyExA [ADVAPI32.@] */ @@ -228,8 +291,7 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); - if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/)) - return ERROR_INVALID_PARAMETER; + if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER; status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); if (status && status != STATUS_BUFFER_OVERFLOW) goto done; @@ -314,6 +376,48 @@ DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name ) } +/****************************************************************************** + * RegSetValueExW [ADVAPI32.@] + * + * Sets the data and type of a value under a register key + * + * PARAMS + * hkey [I] Handle of key to set value for + * name [I] Name of value to set + * reserved [I] Reserved - must be zero + * type [I] Flag for value type + * data [I] Address of value data + * count [I] Size of value data + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + * + * NOTES + * win95 does not care about count for REG_SZ and finds out the len by itself (js) + * NT does definitely care (aj) + */ +DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved, + DWORD type, CONST BYTE *data, DWORD count ) +{ + UNICODE_STRING nameW; + + if (!is_version_nt()) /* win95 */ + { + if (type == REG_SZ) count = (strlenW( (WCHAR *)data ) + 1) * sizeof(WCHAR); + } + else if (count && is_string(type)) + { + LPCWSTR str = (LPCWSTR)data; + /* if user forgot to count terminating null, add it (yes NT does this) */ + if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)]) + count += sizeof(WCHAR); + } + + RtlInitUnicodeString( &nameW, name ); + return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) ); +} + /****************************************************************************** * RegSetValueExA [ADVAPI32.@] @@ -376,6 +480,86 @@ DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWOR } +/****************************************************************************** + * RegQueryValueExW [ADVAPI32.@] + * + * Retrieves type and data for a specified name associated with an open key + * + * PARAMS + * hkey [I] Handle of key to query + * name [I] Name of value to query + * reserved [I] Reserved - must be NULL + * type [O] Address of buffer for value type. If NULL, the type + * is not required. + * data [O] Address of data buffer. If NULL, the actual data is + * not required. + * count [I/O] Address of data buffer size + * + * RETURNS + * ERROR_SUCCESS: Success + * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data + * buffer is left untouched. The MS-documentation is wrong (js) !!! + */ +DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type, + LPBYTE data, LPDWORD count ) +{ + NTSTATUS status; + UNICODE_STRING name_str; + DWORD total_size; + char buffer[256], *buf_ptr = buffer; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + static const int info_size = info->Data - (UCHAR *)info; + + TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n", + hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 ); + + if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + + RtlInitUnicodeString( &name_str, name ); + + if (data) total_size = min( sizeof(buffer), *count + info_size ); + else total_size = info_size; + + status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, + buffer, total_size, &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; + + if (data) + { + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) + { + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); + } + + if (!status) + { + memcpy( data, buf_ptr + info_size, total_size - info_size ); + /* if the type is REG_SZ and data is not 0-terminated + * and there is enough space in the buffer NT appends a \0 */ + if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type)) + { + WCHAR *ptr = (WCHAR *)(data + total_size - info_size); + if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; + } + } + else if (status != STATUS_BUFFER_OVERFLOW) goto done; + } + else status = STATUS_SUCCESS; + + if (type) *type = info->Type; + if (count) *count = total_size - info_size; + + done: + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError(status); +} + /****************************************************************************** * RegQueryValueExA [ADVAPI32.@] @@ -715,3 +899,56 @@ done: SetLastError( err ); /* restore last error code */ return ret; } + + +/****************************************************************************** + * RegUnLoadKeyA [ADVAPI32.@] + * + * PARAMS + * hkey [I] Handle of open key + * lpSubKey [I] Address of name of subkey to unload + */ +LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey ) +{ + FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey)); + return ERROR_SUCCESS; +} + + +/****************************************************************************** + * RegReplaceKeyA [ADVAPI32.@] + * + * PARAMS + * hkey [I] Handle of open key + * lpSubKey [I] Address of name of subkey + * lpNewFile [I] Address of filename for file with new data + * lpOldFile [I] Address of filename for backup file + */ +LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile, + LPCSTR lpOldFile ) +{ + FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey), + debugstr_a(lpNewFile),debugstr_a(lpOldFile)); + return ERROR_SUCCESS; +} + + +/****************************************************************************** + * RegFlushKey [ADVAPI32.@] + * Immediately writes key to registry. + * Only returns after data has been written to disk. + * + * FIXME: does it really wait until data is written ? + * + * PARAMS + * hkey [I] Handle of key to write + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Error code + */ +DWORD WINAPI RegFlushKey( HKEY hkey ) +{ + FIXME( "(%x): stub\n", hkey ); + return ERROR_SUCCESS; +} diff --git a/misc/registry.c b/misc/registry.c index 093d636737e..feb548b0567 100644 --- a/misc/registry.c +++ b/misc/registry.c @@ -1050,16 +1050,21 @@ static void _init_registry_saving( HKEY hkey_users_default ) { int all; int period = 0; - char buffer[20]; + WCHAR buffer[20]; + static const WCHAR registryW[] = {'r','e','g','i','s','t','r','y',0}; + static const WCHAR SaveOnlyUpdatedKeysW[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0}; + static const WCHAR PeriodicSaveW[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0}; + static const WCHAR WritetoHomeRegistryFilesW[] = {'W','r','i','t','e','t','o','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0}; + static const WCHAR empty_strW[] = { 0 }; - all = !PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1); - PROFILE_GetWineIniString( "registry", "PeriodicSave", "", buffer, sizeof(buffer) ); - if (buffer[0]) period = atoi(buffer); + all = !PROFILE_GetWineIniBool(registryW, SaveOnlyUpdatedKeysW, 1); + PROFILE_GetWineIniString( registryW, PeriodicSaveW, empty_strW, buffer, 20 ); + if (buffer[0]) period = (int)strtolW(buffer, NULL, 10); /* set saving level (0 for saving everything, 1 for saving only modified keys) */ _set_registry_levels(1,!all,period*1000); - if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1)) + if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1)) { _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER ); _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE); @@ -1118,29 +1123,33 @@ static void _allocate_default_keys(void) { /* return the type of native registry [Internal] */ static int _get_reg_type(void) { - char windir[MAX_PATHNAME_LEN]; - char tmp[MAX_PATHNAME_LEN]; + WCHAR windir[MAX_PATHNAME_LEN]; + WCHAR tmp[MAX_PATHNAME_LEN]; int ret = REG_WIN31; + static const WCHAR nt_reg_pathW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0}; + static const WCHAR win9x_reg_pathW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0}; + static const WCHAR WineW[] = {'W','i','n','e',0}; + static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0}; + static const WCHAR empty_strW[] = { 0 }; - GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN); + GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN); /* test %windir%/system32/config/system --> winnt */ - strcpy(tmp, windir); - strncat(tmp, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(tmp) - 1); - if(GetFileAttributesA(tmp) != (DWORD)-1) { + strcpyW(tmp, windir); + strcatW(tmp, nt_reg_pathW); + if(GetFileAttributesW(tmp) != (DWORD)-1) ret = REG_WINNT; - } else { /* test %windir%/system.dat --> win95 */ - strcpy(tmp, windir); - strncat(tmp, "\\system.dat", MAX_PATHNAME_LEN - strlen(tmp) - 1); - if(GetFileAttributesA(tmp) != (DWORD)-1) { + strcpyW(tmp, windir); + strcatW(tmp, win9x_reg_pathW); + if(GetFileAttributesW(tmp) != (DWORD)-1) ret = REG_WIN95; - } } - if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp, MAX_PATHNAME_LEN))) { + if ((ret == REG_WINNT) && (!PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, tmp, MAX_PATHNAME_LEN ))) + { MESSAGE("When you are running with a native NT directory specify\n"); MESSAGE("'Profile=' or disable loading of Windows\n"); MESSAGE("registry (LoadWindowsRegistryFiles=N)\n"); @@ -1255,7 +1264,7 @@ static LPSTR _get_tmp_fn(FILE **f) } /* convert win95 native registry file to wine format [Internal] */ -static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level) +static LPSTR _convert_win95_registry_to_wine_format(LPCWSTR fn, int level) { int fd; FILE *f; @@ -1278,7 +1287,8 @@ static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level) /* control signature */ if (*(LPDWORD)base != W95_REG_CREG_ID) { - ERR("unable to load native win95 registry file %s: unknown signature.\n",fn); + ERR("unable to load native win95 registry file %s: unknown signature.\n", + debugstr_w(fn)); goto error; } @@ -1324,7 +1334,7 @@ static LPSTR _convert_win95_registry_to_wine_format(LPCSTR fn,int level) error: if(ret == NULL) { - ERR("Unable to load native win95 registry file %s.\n",fn); + ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn)); ERR("Please report this.\n"); ERR("Make a backup of the file, run a good reg cleaner program and try again!\n"); } @@ -1336,7 +1346,7 @@ error1: } /* convert winnt native registry file to wine format [Internal] */ -static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level) +static LPSTR _convert_winnt_registry_to_wine_format(LPCWSTR fn, int level) { FILE *f; void *base; @@ -1349,11 +1359,11 @@ static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level) nt_hbin_sub *hbin_sub; nt_nk *nk; - TRACE("%s\n", fn); + TRACE("%s\n", debugstr_w(fn)); - hFile = CreateFileA( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + hFile = CreateFileW( fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); if ( hFile == INVALID_HANDLE_VALUE ) return NULL; - hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL ); + hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY|SEC_COMMIT, 0, 0, NULL ); if (!hMapping) goto error1; base = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 ); CloseHandle( hMapping ); @@ -1361,7 +1371,8 @@ static LPSTR _convert_winnt_registry_to_wine_format(LPCSTR fn,int level) /* control signature */ if (*(LPDWORD)base != NT_REG_HEADER_BLOCK_ID) { - ERR("unable to load native winnt registry file %s: unknown signature.\n",fn); + ERR("unable to load native winnt registry file %s: unknown signature.\n", + debugstr_w(fn)); goto error; } @@ -1402,7 +1413,7 @@ error1: } /* convert native registry to wine format and load it via server call [Internal] */ -static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,int level) +static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_type, int level) { LPSTR tmp = NULL; @@ -1424,10 +1435,11 @@ static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,i if (tmp != NULL) { load_wine_registry(hkey,tmp); - TRACE("File %s successfully converted to %s and loaded to registry.\n",fn,tmp); + TRACE("File %s successfully converted to %s and loaded to registry.\n", + debugstr_w(fn), tmp); unlink(tmp); } - else WARN("Unable to convert %s (doesn't exist?)\n",fn); + else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn)); free(tmp); } @@ -1435,26 +1447,35 @@ static void _convert_and_load_native_registry(LPCSTR fn,HKEY hkey,int reg_type,i static void _load_windows_registry( HKEY hkey_users_default ) { int reg_type; - char windir[MAX_PATHNAME_LEN]; - char path[MAX_PATHNAME_LEN]; + WCHAR windir[MAX_PATHNAME_LEN]; + WCHAR path[MAX_PATHNAME_LEN]; + static const WCHAR WineW[] = {'W','i','n','e',0}; + static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0}; + static const WCHAR empty_strW[] = { 0 }; - GetWindowsDirectoryA(windir,MAX_PATHNAME_LEN); + GetWindowsDirectoryW(windir, MAX_PATHNAME_LEN); reg_type = _get_reg_type(); switch (reg_type) { case REG_WINNT: { HKEY hkey; + static const WCHAR ntuser_datW[] = {'\\','n','t','u','s','e','r','.','d','a','t',0}; + static const WCHAR defaultW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','d','e','f','a','u','l','t',0}; + static const WCHAR systemW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0}; + static const WCHAR softwareW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','o','f','t','w','a','r','e',0}; + static const WCHAR samW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0}; + static const WCHAR securityW[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','e','c','u','r','i','t','y',0}; /* user specific ntuser.dat */ - if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)) { - strcat(path,"\\ntuser.dat"); + if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) { + strcatW(path, ntuser_datW); _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1); } /* default user.dat */ if (hkey_users_default) { - strcpy(path,windir); - strcat(path,"\\system32\\config\\default"); + strcpyW(path, windir); + strcatW(path, defaultW); _convert_and_load_native_registry(path,hkey_users_default,REG_WINNT,1); } @@ -1464,25 +1485,25 @@ static void _load_windows_registry( HKEY hkey_users_default ) */ if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey)) { - strcpy(path,windir); - strcat(path,"\\system32\\config\\system"); + strcpyW(path, windir); + strcatW(path, systemW); _convert_and_load_native_registry(path,hkey,REG_WINNT,1); RegCloseKey(hkey); } if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey)) { - strcpy(path,windir); - strcat(path,"\\system32\\config\\software"); + strcpyW(path, windir); + strcatW(path, softwareW); _convert_and_load_native_registry(path,hkey,REG_WINNT,1); RegCloseKey(hkey); } - strcpy(path,windir); - strcat(path,"\\system32\\config\\sam"); + strcpyW(path, windir); + strcatW(path, samW); _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0); - strcpy(path,windir); - strcat(path,"\\system32\\config\\security"); + strcpyW(path,windir); + strcatW(path, securityW); _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WINNT,0); /* this key is generated when the nt-core booted successfully */ @@ -1491,33 +1512,40 @@ static void _load_windows_registry( HKEY hkey_users_default ) } case REG_WIN95: - _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE,REG_WIN95,0); + { + static const WCHAR system_1stW[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0}; + static const WCHAR system_datW[] = {'\\','s','y','s','t','e','m','.','d','a','t',0}; + static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0}; + static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0}; - strcpy(path,windir); - strcat(path,"\\system.dat"); + _convert_and_load_native_registry(system_1stW,HKEY_LOCAL_MACHINE,REG_WIN95,0); + + strcpyW(path, windir); + strcatW(path, system_datW); _convert_and_load_native_registry(path,HKEY_LOCAL_MACHINE,REG_WIN95,0); - strcpy(path,windir); - strcat(path,"\\classes.dat"); + strcpyW(path, windir); + strcatW(path, classes_datW); _convert_and_load_native_registry(path,HKEY_CLASSES_ROOT,REG_WIN95,0); - if (PROFILE_GetWineIniString("Wine","Profile","",path,MAX_PATHNAME_LEN)) { + if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) { /* user specific user.dat */ - strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1); + strcatW(path, user_datW); _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1); /* default user.dat */ if (hkey_users_default) { - strcpy(path,windir); - strcat(path,"\\user.dat"); + strcpyW(path, windir); + strcatW(path, user_datW); _convert_and_load_native_registry(path,hkey_users_default,REG_WIN95,1); } } else { - strcpy(path,windir); - strcat(path,"\\user.dat"); + strcpyW(path, windir); + strcatW(path, user_datW); _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1); } break; + } case REG_WIN31: /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */ @@ -1572,6 +1600,10 @@ static void _load_home_registry( HKEY hkey_users_default ) void SHELL_LoadRegistry( void ) { HKEY hkey_users_default; + static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0}; + static const WCHAR load_win_reg_filesW[] = {'L','o','a','d','W','i','n','d','o','w','s','R','e','g','i','s','t','r','y','F','i','l','e','s',0}; + static const WCHAR load_global_reg_filesW[] = {'L','o','a','d','G','l','o','b','a','l','R','e','g','i','s','t','r','y','F','i','l','e','s',0}; + static const WCHAR load_home_reg_filesW[] = {'L','o','a','d','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0}; TRACE("(void)\n"); @@ -1585,70 +1617,21 @@ void SHELL_LoadRegistry( void ) _allocate_default_keys(); _set_registry_levels(0,0,0); - if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1)) + if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1)) _load_windows_registry( hkey_users_default ); - if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1)) + if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1)) _load_global_registry(); _set_registry_levels(1,0,0); - if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1)) + if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1)) _load_home_registry( hkey_users_default ); _init_registry_saving( hkey_users_default ); RegCloseKey(hkey_users_default); } /***************************************************************************/ -/* API FUNCTIONS */ +/* 16-BIT API FUNCTIONS */ /***************************************************************************/ -/****************************************************************************** - * RegFlushKey [ADVAPI32.@] - * Immediately writes key to registry. - * Only returns after data has been written to disk. - * - * FIXME: does it really wait until data is written ? - * - * PARAMS - * hkey [I] Handle of key to write - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Error code - */ -DWORD WINAPI RegFlushKey( HKEY hkey ) -{ - FIXME( "(%x): stub\n", hkey ); - return ERROR_SUCCESS; -} - - -/****************************************************************************** - * RegUnLoadKeyA [ADVAPI32.@] - */ -LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey ) -{ - FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey)); - return ERROR_SUCCESS; -} - - -/****************************************************************************** - * RegReplaceKeyA [ADVAPI32.@] - */ -LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile, - LPCSTR lpOldFile ) -{ - FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey), - debugstr_a(lpNewFile),debugstr_a(lpOldFile)); - return ERROR_SUCCESS; -} - - - - - - -/* 16-bit functions */ - /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by * some programs. Do not remove those cases. -MM */ diff --git a/msdos/dosconf.c b/msdos/dosconf.c index f2978948e22..636e8f738f5 100644 --- a/msdos/dosconf.c +++ b/msdos/dosconf.c @@ -435,17 +435,19 @@ static void DOSCONF_Parse(char *menuname) int DOSCONF_ReadConfig(void) { - char buffer[256]; + WCHAR filename[MAX_PATH]; DOS_FULL_NAME fullname; - char *filename, *menuname; + WCHAR *p; int ret = 1; + static const WCHAR wineW[] = {'w','i','n','e',0}; + static const WCHAR config_sysW[] = {'c','o','n','f','i','g','.','s','y','s',0}; + static const WCHAR empty_strW[] = { 0 }; - PROFILE_GetWineIniString( "wine", "config.sys", "", buffer, sizeof(buffer) ); - if (!(filename = strtok(buffer, ","))) return ret; - menuname = strtok(NULL, ","); + PROFILE_GetWineIniString( wineW, config_sysW, empty_strW, filename, MAX_PATH ); + if ((p = strchrW(filename, ','))) *p = 0; + if (!filename[0]) return ret; DOSFS_GetFullName(filename, FALSE, &fullname); - if (menuname) menu_default = strdup(menuname); if ((cfg_fd = fopen(fullname.long_name, "r"))) { DOSCONF_Parse(NULL); @@ -453,10 +455,9 @@ int DOSCONF_ReadConfig(void) } else { - MESSAGE("Couldn't open config.sys file given as \"%s\" in" \ - " wine.conf or .winerc, section [wine] !\n", filename); + MESSAGE("Couldn't open config.sys file given as %s in" \ + " wine.conf or .winerc, section [wine] !\n", debugstr_w(filename)); ret = 0; } - if (menu_default) free(menu_default); return ret; } diff --git a/msdos/int11.c b/msdos/int11.c index d7ac9d70e54..bdcd34dc630 100644 --- a/msdos/int11.c +++ b/msdos/int11.c @@ -28,6 +28,7 @@ #include "miscemu.h" #include "msdos.h" #include "file.h" +#include "wine/unicode.h" #include "wine/debug.h" /********************************************************************** @@ -74,16 +75,21 @@ void WINAPI INT_Int11Handler( CONTEXT86 *context ) for (x=0; x < 9; x++) { - char temp[16],name[16]; + WCHAR temp[16]; + WCHAR comW[] = {'C','O','M','?',0}; + WCHAR lptW[] = {'L','P','T','?',0}; + static const WCHAR serialportsW[] = {'s','e','r','i','a','l','p','o','r','t','s',0}; + static const WCHAR parallelportsW[] = {'p','a','r','a','l','l','e','l','p','o','r','t','s',0}; + static const WCHAR asteriskW[] = {'*',0}; - sprintf(name,"COM%d",x+1); - PROFILE_GetWineIniString("serialports",name,"*",temp,sizeof temp); - if(strcmp(temp,"*")) + comW[3] = '0' + x; + PROFILE_GetWineIniString(serialportsW, comW, asteriskW, temp, 16); + if(strcmpW(temp, asteriskW)) serialports++; - sprintf(name,"LPT%d",x+1); - PROFILE_GetWineIniString("parallelports",name,"*",temp,sizeof temp); - if(strcmp(temp,"*")) + lptW[3] = '0' + x; + PROFILE_GetWineIniString(parallelportsW, lptW, asteriskW, temp, 16); + if(strcmpW(temp, asteriskW)) parallelports++; } if (serialports > 7) /* 3 bits -- maximum value = 7 */ diff --git a/msdos/int21.c b/msdos/int21.c index cf7b3f3e309..d4851e0657e 100644 --- a/msdos/int21.c +++ b/msdos/int21.c @@ -57,6 +57,7 @@ #include "msdos.h" #include "miscemu.h" #include "task.h" +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(int21); @@ -428,30 +429,37 @@ static void INT21_ParseFileNameIntoFCB( CONTEXT86 *context ) CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Esi ); char *fcb = CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Edi ); - char *buffer, *s, *d; + char *s; + WCHAR *buffer; + WCHAR fcbW[12]; + INT buffer_len, len; AL_reg(context) = 0xff; /* failed */ TRACE("filename: '%s'\n", filename); - buffer = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 1); - s = filename; - d = buffer; + len = 0; while (*s) { if ((*s != ' ') && (*s != '\r') && (*s != '\n')) - *d++ = *s++; + { + s++; + len++; + } else break; } - *d = '\0'; - DOSFS_ToDosFCBFormat(buffer, fcb + 1); + 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", ((CHAR *)fcb + 1)); - - HeapFree( GetProcessHeap(), 0, buffer); + TRACE("FCB: '%s'\n", fcb + 1); AL_reg(context) = ((strchr(filename, '*')) || (strchr(filename, '$'))) != 0; @@ -618,6 +626,7 @@ static BOOL INT21_ChangeDir( CONTEXT86 *context ) { int drive; char *dirname = CTX_SEG_OFF_TO_LIN(context, context->SegDs,context->Edx); + WCHAR dirnameW[MAX_PATH]; TRACE("changedir %s\n", dirname); if (dirname[0] && (dirname[1] == ':')) @@ -626,7 +635,8 @@ static BOOL INT21_ChangeDir( CONTEXT86 *context ) dirname += 2; } else drive = DRIVE_GetCurrentDrive(); - return DRIVE_Chdir( drive, dirname ); + MultiByteToWideChar(CP_OEMCP, 0, dirname, -1, dirnameW, MAX_PATH); + return DRIVE_Chdir( drive, dirnameW ); } @@ -636,10 +646,14 @@ static int INT21_FindFirst( CONTEXT86 *context ) 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( path, FALSE, &full_name )) + if (!DOSFS_GetFullName( pathW, FALSE, &full_name )) { AX_reg(context) = GetLastError(); SET_CFLAG(context); @@ -650,10 +664,12 @@ static int INT21_FindFirst( CONTEXT86 *context ) 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( p + 1, dta->mask )) + if (!DOSFS_ToDosFCBFormat( pathW, maskW )) { HeapFree( GetProcessHeap(), 0, dta->unixPath ); dta->unixPath = NULL; @@ -662,6 +678,7 @@ static int INT21_FindFirst( CONTEXT86 *context ) 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; @@ -743,7 +760,8 @@ static BOOL INT21_GetCurrentDirectory( CONTEXT86 *context ) SetLastError( ERROR_INVALID_DRIVE ); return FALSE; } - lstrcpynA( ptr, DRIVE_GetDosCwd(drive), 64 ); + WideCharToMultiByte(CP_OEMCP, 0, DRIVE_GetDosCwd(drive), -1, ptr, 64, NULL, NULL); + ptr[63] = 0; /* ensure 0 termination */ AX_reg(context) = 0x0100; /* success return code */ return TRUE; } @@ -1586,8 +1604,9 @@ void WINAPI DOS3Call( CONTEXT86 *context ) break; case 0x02:{ const DOS_DEVICE *dev; + static const WCHAR scsimgrW[] = {'S','C','S','I','M','G','R','$',0}; if ((dev = DOSFS_GetDeviceByHandle( DosFileHandleToWin32Handle(BX_reg(context)) )) && - !strcasecmp( dev->name, "SCSIMGR$" )) + !strcmpiW( dev->name, scsimgrW )) { ASPI_DOS_HandleInt(context); } diff --git a/msdos/ioports.c b/msdos/ioports.c index 3a36ce345df..f8e3b7c2c8e 100644 --- a/msdos/ioports.c +++ b/msdos/ioports.c @@ -36,6 +36,7 @@ # include #endif #include "windef.h" +#include "winnls.h" #include "callback.h" #include "file.h" #include "miscemu.h" @@ -249,17 +250,22 @@ static inline void outl( DWORD value, WORD port ) static void IO_port_init(void) { char temp[1024]; + WCHAR tempW[1024]; + static const WCHAR portsW[] = {'p','o','r','t','s',0}; + static const WCHAR readW[] = {'r','e','a','d',0}; + static const WCHAR writeW[] = {'w','r','i','t','e',0}; + static const WCHAR asteriskW[] = {'*',0}; do_direct_port_access = 0; /* Can we do that? */ if (!iopl(3)) { iopl(0); - PROFILE_GetWineIniString( "ports", "read", "*", - temp, sizeof(temp) ); + PROFILE_GetWineIniString( portsW, readW, asteriskW, tempW, 1024 ); + WideCharToMultiByte(CP_ACP, 0, tempW, -1, temp, 1024, NULL, NULL); do_IO_port_init_read_or_write(temp, IO_READ); - PROFILE_GetWineIniString( "ports", "write", "*", - temp, sizeof(temp) ); + PROFILE_GetWineIniString( portsW, writeW, asteriskW, tempW, 1024 ); + WideCharToMultiByte(CP_ACP, 0, tempW, -1, temp, 1024, NULL, NULL); do_IO_port_init_read_or_write(temp, IO_WRITE); } IO_FixCMOSCheckSum(); diff --git a/scheduler/process.c b/scheduler/process.c index b3efdff8f0a..606f376b39f 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -650,9 +650,12 @@ void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win { DOS_FULL_NAME full_name; const char *name = main_exe_name; + UNICODE_STRING nameW; TRACE( "starting Winelib app %s\n", debugstr_a(main_exe_name) ); - if (DOSFS_GetFullName( name, TRUE, &full_name )) name = full_name.long_name; + RtlCreateUnicodeStringFromAsciiz(&nameW, name); + if (DOSFS_GetFullName( nameW.Buffer, TRUE, &full_name )) name = full_name.long_name; + RtlFreeUnicodeString(&nameW); CloseHandle( main_exe_file ); main_exe_file = 0; if (wine_dlopen( name, RTLD_NOW, error, sizeof(error) )) @@ -1194,13 +1197,16 @@ BOOL WINAPI CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUT if (cur_dir) { - if (DOSFS_GetFullName( cur_dir, TRUE, &full_dir )) + UNICODE_STRING cur_dirW; + RtlCreateUnicodeStringFromAsciiz(&cur_dirW, cur_dir); + if (DOSFS_GetFullName( cur_dirW.Buffer, TRUE, &full_dir )) unixdir = full_dir.long_name; + RtlFreeUnicodeString(&cur_dirW); } else { - char buf[MAX_PATH]; - if (GetCurrentDirectoryA(sizeof(buf),buf)) + WCHAR buf[MAX_PATH]; + if (GetCurrentDirectoryW(MAX_PATH, buf)) { if (DOSFS_GetFullName( buf, TRUE, &full_dir )) unixdir = full_dir.long_name; } @@ -1253,11 +1259,16 @@ BOOL WINAPI CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUT /* fall through */ case BINARY_UNIX_EXE: { + /* unknown file, try as unix executable */ + UNICODE_STRING nameW; DOS_FULL_NAME full_name; const char *unixfilename = name; TRACE( "starting %s as Unix binary\n", debugstr_a(name) ); - if (DOSFS_GetFullName( name, TRUE, &full_name )) unixfilename = full_name.long_name; + + RtlCreateUnicodeStringFromAsciiz(&nameW, name); + if (DOSFS_GetFullName( nameW.Buffer, TRUE, &full_name )) unixfilename = full_name.long_name; + RtlFreeUnicodeString(&nameW); retv = (fork_and_exec( unixfilename, tidy_cmdline, env, unixdir ) != -1); } break; diff --git a/win32/device.c b/win32/device.c index 8da2d72f403..f5a6944feac 100644 --- a/win32/device.c +++ b/win32/device.c @@ -344,9 +344,16 @@ LPCSTR VMM_Service_Name[N_VMM_SERVICE] = -HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa ) +HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa ) { const struct VxDInfo *info; + char filename[MAX_PATH]; + + if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL)) + { + SetLastError( ERROR_FILE_NOT_FOUND ); + return 0; + } for (info = VxDList; info->name; info++) if (!strncasecmp( info->name, filename, strlen(info->name) )) @@ -1563,4 +1570,3 @@ static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInB return retv; } -