winemenubuilder: Escape freedesktop exec keys properly.

This commit is contained in:
Damjan Jovanovic 2010-05-08 23:20:32 +02:00 committed by Alexandre Julliard
parent c545982472
commit 745747688d
1 changed files with 105 additions and 67 deletions

View File

@ -792,6 +792,36 @@ static BOOL create_directories(char *directory)
return ret; return ret;
} }
static char* wchars_to_utf8_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UTF8, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static char* wchars_to_unix_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UNIXCP, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UNIXCP, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static WCHAR* utf8_chars_to_wchars(LPCSTR string)
{
WCHAR *ret;
INT size = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_UTF8, 0, string, -1, ret, size);
return ret;
}
/* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */ /* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
static char *extract_icon( LPCWSTR path, int index, const char *destFilename, BOOL bWait ) static char *extract_icon( LPCWSTR path, int index, const char *destFilename, BOOL bWait )
{ {
@ -945,7 +975,7 @@ static BOOL write_desktop_entry(const char *unix_link, const char *location, con
fprintf(file, "[Desktop Entry]\n"); fprintf(file, "[Desktop Entry]\n");
fprintf(file, "Name=%s\n", linkname); fprintf(file, "Name=%s\n", linkname);
fprintf(file, "Exec=env WINEPREFIX=\"%s\" wine \"%s\" %s\n", fprintf(file, "Exec=env WINEPREFIX=\"%s\" wine %s %s\n",
wine_get_config_dir(), path, args); wine_get_config_dir(), path, args);
fprintf(file, "Type=Application\n"); fprintf(file, "Type=Application\n");
fprintf(file, "StartupNotify=true\n"); fprintf(file, "StartupNotify=true\n");
@ -1154,35 +1184,63 @@ end:
return ret; return ret;
} }
/* This escapes \ in filenames */ /* This escapes reserved characters in .desktop files' Exec keys. */
static LPSTR escape(LPCWSTR arg) static LPSTR escape(LPCWSTR arg)
{ {
LPSTR narg, x; int i, j;
LPCWSTR esc; WCHAR *escaped_string;
int len = 0, n; char *utf8_string;
esc = arg; escaped_string = HeapAlloc(GetProcessHeap(), 0, (4 * strlenW(arg) + 1) * sizeof(WCHAR));
while((esc = strchrW(esc, '\\'))) if (escaped_string == NULL) return NULL;
for (i = j = 0; arg[i]; i++)
{ {
esc++; switch (arg[i])
len++; {
case '\\':
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
break;
case ' ':
case '\t':
case '\n':
case '"':
case '\'':
case '>':
case '<':
case '~':
case '|':
case '&':
case ';':
case '$':
case '*':
case '?':
case '#':
case '(':
case ')':
case '`':
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
/* fall through */
default:
escaped_string[j++] = arg[i];
break;
}
}
escaped_string[j] = 0;
utf8_string = wchars_to_utf8_chars(escaped_string);
if (utf8_string == NULL)
{
WINE_ERR("out of memory\n");
goto end;
} }
len += WideCharToMultiByte(CP_UNIXCP, 0, arg, -1, NULL, 0, NULL, NULL); end:
narg = HeapAlloc(GetProcessHeap(), 0, len); HeapFree(GetProcessHeap(), 0, escaped_string);
return utf8_string;
x = narg;
while (*arg)
{
n = WideCharToMultiByte(CP_UNIXCP, 0, arg, 1, x, len, NULL, NULL);
x += n;
len -= n;
if (*arg == '\\')
*x++='\\'; /* escape \ */
arg++;
}
*x = 0;
return narg;
} }
/* Return a heap-allocated copy of the unix format difference between the two /* Return a heap-allocated copy of the unix format difference between the two
@ -1424,36 +1482,6 @@ static WCHAR* assoc_query(ASSOCSTR assocStr, LPCWSTR name, LPCWSTR extra)
return value; return value;
} }
static char* wchars_to_utf8_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UTF8, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static char* wchars_to_unix_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UNIXCP, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UNIXCP, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static WCHAR* utf8_chars_to_wchars(LPCSTR string)
{
WCHAR *ret;
INT size = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_UTF8, 0, string, -1, ret, size);
return ret;
}
static char *slashes_to_minuses(const char *string) static char *slashes_to_minuses(const char *string)
{ {
int i; int i;
@ -2135,7 +2163,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL); progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL);
if (progIdW) if (progIdW)
{ {
progIdA = wchars_to_utf8_chars(progIdW); progIdA = escape(progIdW);
if (progIdA == NULL) if (progIdA == NULL)
{ {
WINE_ERR("out of memory\n"); WINE_ERR("out of memory\n");
@ -2187,7 +2215,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
static const WCHAR startW[] = {'\\','c','o','m','m','a','n','d', static const WCHAR startW[] = {'\\','c','o','m','m','a','n','d',
'\\','s','t','a','r','t','.','e','x','e',0}; '\\','s','t','a','r','t','.','e','x','e',0};
char *link_name = NULL, *icon_name = NULL, *work_dir = NULL; char *link_name = NULL, *icon_name = NULL, *work_dir = NULL;
char *escaped_path = NULL, *escaped_args = NULL, *escaped_description = NULL; char *escaped_path = NULL, *escaped_args = NULL, *description = NULL;
WCHAR szTmp[INFOTIPSIZE]; WCHAR szTmp[INFOTIPSIZE];
WCHAR szDescription[INFOTIPSIZE], szPath[MAX_PATH], szWorkDir[MAX_PATH]; WCHAR szDescription[INFOTIPSIZE], szPath[MAX_PATH], szWorkDir[MAX_PATH];
WCHAR szArgs[INFOTIPSIZE], szIconPath[MAX_PATH]; WCHAR szArgs[INFOTIPSIZE], szIconPath[MAX_PATH];
@ -2311,7 +2339,12 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
/* escape the path and parameters */ /* escape the path and parameters */
escaped_path = escape(szPath); escaped_path = escape(szPath);
escaped_args = escape(szArgs); escaped_args = escape(szArgs);
escaped_description = escape(szDescription); description = wchars_to_utf8_chars(szDescription);
if (escaped_path == NULL || escaped_args == NULL || description == NULL)
{
WINE_ERR("out of memory allocating/escaping parameters\n");
goto cleanup;
}
/* building multiple menus concurrently has race conditions */ /* building multiple menus concurrently has race conditions */
hsem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore"); hsem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
@ -2333,7 +2366,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
location = heap_printf("%s/%s.desktop", xdg_desktop_dir, lastEntry); location = heap_printf("%s/%s.desktop", xdg_desktop_dir, lastEntry);
if (location) if (location)
{ {
r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, escaped_description, work_dir, icon_name); r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, description, work_dir, icon_name);
if (r == 0) if (r == 0)
chmod(location, 0755); chmod(location, 0755);
HeapFree(GetProcessHeap(), 0, location); HeapFree(GetProcessHeap(), 0, location);
@ -2341,21 +2374,21 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
} }
else else
{ {
char *arg = heap_printf("/Unix \"%s\"", unix_link); WCHAR *unix_linkW = utf8_chars_to_wchars(unix_link);
if (arg) if (unix_linkW)
{ {
WCHAR *warg = utf8_chars_to_wchars(arg); char *escaped_lnk = escape(unix_linkW);
if (warg) if (escaped_lnk)
{ {
char *menuarg = escape(warg); char *menuarg = heap_printf("/Unix %s", escaped_lnk);
if (menuarg) if (menuarg)
{ {
r = !write_menu_entry(unix_link, link_name, "start", menuarg, escaped_description, work_dir, icon_name); r = !write_menu_entry(unix_link, link_name, "start", menuarg, description, work_dir, icon_name);
HeapFree(GetProcessHeap(), 0, menuarg); HeapFree(GetProcessHeap(), 0, menuarg);
} }
HeapFree(GetProcessHeap(), 0, warg); HeapFree(GetProcessHeap(), 0, escaped_lnk);
} }
HeapFree(GetProcessHeap(), 0, arg); HeapFree(GetProcessHeap(), 0, unix_linkW);
} }
} }
@ -2368,7 +2401,7 @@ cleanup:
HeapFree( GetProcessHeap(), 0, link_name ); HeapFree( GetProcessHeap(), 0, link_name );
HeapFree( GetProcessHeap(), 0, escaped_args ); HeapFree( GetProcessHeap(), 0, escaped_args );
HeapFree( GetProcessHeap(), 0, escaped_path ); HeapFree( GetProcessHeap(), 0, escaped_path );
HeapFree( GetProcessHeap(), 0, escaped_description ); HeapFree( GetProcessHeap(), 0, description );
HeapFree( GetProcessHeap(), 0, unix_link); HeapFree( GetProcessHeap(), 0, unix_link);
if (r && !bWait) if (r && !bWait)
@ -2424,6 +2457,11 @@ static BOOL InvokeShellLinkerForURL( IUniformResourceLocatorW *url, LPCWSTR link
} }
escaped_urlPath = escape(urlPath); escaped_urlPath = escape(urlPath);
if (escaped_urlPath == NULL)
{
WINE_ERR("couldn't escape url, out of memory\n");
goto cleanup;
}
hSem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore"); hSem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
if( WAIT_OBJECT_0 != MsgWaitForMultipleObjects( 1, &hSem, FALSE, INFINITE, QS_ALLINPUT ) ) if( WAIT_OBJECT_0 != MsgWaitForMultipleObjects( 1, &hSem, FALSE, INFINITE, QS_ALLINPUT ) )