From d18465088705bfbb39e5ee50bd7660773c9de51f Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 9 Oct 2012 15:48:47 +0200 Subject: [PATCH] appwiz.cpl: Cache downloaded addon MSI files. --- dlls/appwiz.cpl/addons.c | 126 ++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index 82a6797abf7..efb6cf04622 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -17,10 +17,12 @@ */ #include "config.h" +#include "wine/port.h" #include #include #include +#include #ifdef HAVE_UNISTD_H # include #endif @@ -105,6 +107,10 @@ static const addon_info_t *addon; static HWND install_dialog = NULL; static LPWSTR url = NULL; +static WCHAR * (CDECL *p_wine_get_dos_file_name)(const char*); +static const WCHAR kernel32_dllW[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; + + /* SHA definitions are copied from advapi32. They aren't available in headers. */ typedef struct { @@ -153,13 +159,7 @@ static BOOL sha_check(const WCHAR *file_name) sprintf(buf + i*2, "%02x", *((unsigned char*)sha+i)); if(strcmp(buf, addon->sha)) { - WCHAR message[256]; - WARN("Got %s, expected %s\n", buf, addon->sha); - - if(LoadStringW(hInst, IDS_INVALID_SHA, message, sizeof(message)/sizeof(WCHAR))) - MessageBoxW(NULL, message, NULL, MB_ICONERROR); - return FALSE; } @@ -201,9 +201,6 @@ static enum install_res install_from_unix_file(const char *dir, const char *subd int fd, len; enum install_res ret; - static WCHAR * (CDECL *wine_get_dos_file_name)(const char*); - static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; - len = strlen(dir); file_path = heap_alloc(len+strlen(subdir)+strlen(file_name)+3); if(!file_path) @@ -228,11 +225,8 @@ static enum install_res install_from_unix_file(const char *dir, const char *subd close(fd); - if(!wine_get_dos_file_name) - wine_get_dos_file_name = (void*)GetProcAddress(GetModuleHandleW(kernel32W), "wine_get_dos_file_name"); - - if(wine_get_dos_file_name) { /* Wine UNIX mode */ - dos_file_name = wine_get_dos_file_name(file_path); + if(p_wine_get_dos_file_name) { /* Wine UNIX mode */ + dos_file_name = p_wine_get_dos_file_name(file_path); if(!dos_file_name) { ERR("Could not get dos file name of %s\n", debugstr_a(file_path)); heap_free(file_path); @@ -334,6 +328,90 @@ static enum install_res install_from_default_dir(void) return ret; } +static WCHAR *get_cache_file_name(BOOL ensure_exists) +{ + const char *home_dir = NULL, *xdg_cache_dir; + size_t len, size = strlen(addon->file_name) + 7; /* strlen("/wine/"), '\0' */ + char *cache_file_name; + WCHAR *ret; + + /* non-Wine (eg. Windows) cache is currently not supported */ + if(!p_wine_get_dos_file_name) + return NULL; + + xdg_cache_dir = getenv("XDG_CACHE_HOME"); + if(xdg_cache_dir && *xdg_cache_dir) { + size += strlen(xdg_cache_dir); + }else { + home_dir = getenv("HOME"); + if(!home_dir) + return NULL; + + size += strlen(home_dir) + 8; /* strlen("/.cache/") */ + } + + cache_file_name = heap_alloc(size); + if(!cache_file_name) + return NULL; + + if(xdg_cache_dir && *xdg_cache_dir) { + len = strlen(xdg_cache_dir); + if(len > 1 && xdg_cache_dir[len-1] == '/') + len--; + memcpy(cache_file_name, xdg_cache_dir, len); + cache_file_name[len] = 0; + }else { + len = strlen(home_dir); + memcpy(cache_file_name, home_dir, len); + strcpy(cache_file_name+len, "/.cache"); + len += 7; + } + + if(ensure_exists && mkdir(cache_file_name, 0777) && errno != EEXIST) { + WARN("%s does not exist and could not be created: %s\n", cache_file_name, strerror(errno)); + heap_free(cache_file_name); + return NULL; + } + + strcpy(cache_file_name+len, "/wine"); + len += 5; + + if(ensure_exists && mkdir(cache_file_name, 0777) && errno != EEXIST) { + WARN("%s does not exist and could not be created: %s\n", cache_file_name, strerror(errno)); + return NULL; + } + + cache_file_name[len++] = '/'; + strcpy(cache_file_name+len, addon->file_name); + ret = p_wine_get_dos_file_name(cache_file_name); + + TRACE("%s -> %s\n", cache_file_name, debugstr_w(ret)); + + heap_free(cache_file_name); + return ret; +} + +static enum install_res install_from_cache(void) +{ + WCHAR *cache_file_name; + enum install_res res; + + cache_file_name = get_cache_file_name(FALSE); + if(!cache_file_name) + return INSTALL_NEXT; + + if(!sha_check(cache_file_name)) { + WARN("could not validate check sum\n"); + DeleteFileW(cache_file_name); + heap_free(cache_file_name); + return INSTALL_NEXT; + } + + res = install_file(cache_file_name); + heap_free(cache_file_name); + return res; +} + static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv) { @@ -501,8 +579,23 @@ static DWORD WINAPI download_proc(PVOID arg) return 0; } - if(sha_check(tmp_file)) + if(sha_check(tmp_file)) { + WCHAR *cache_file_name; + install_file(tmp_file); + + cache_file_name = get_cache_file_name(TRUE); + if(cache_file_name) { + MoveFileW(tmp_file, cache_file_name); + heap_free(cache_file_name); + } + }else { + WCHAR message[256]; + + if(LoadStringW(hInst, IDS_INVALID_SHA, message, sizeof(message)/sizeof(WCHAR))) + MessageBoxW(NULL, message, NULL, MB_ICONERROR); + } + DeleteFileW(tmp_file); EndDialog(install_dialog, 0); return 0; @@ -589,6 +682,8 @@ BOOL install_addon(addon_t addon_type) addon = addons_info+addon_type; + p_wine_get_dos_file_name = (void*)GetProcAddress(GetModuleHandleW(kernel32_dllW), "wine_get_dos_file_name"); + /* * Try to find addon .msi file in following order: * - directory stored in $dir_config_key value of HKCU/Wine/Software/$config_key key @@ -599,6 +694,7 @@ BOOL install_addon(addon_t addon_type) */ if (install_from_registered_dir() == INSTALL_NEXT && install_from_default_dir() == INSTALL_NEXT + && install_from_cache() == INSTALL_NEXT && (url = get_url())) DialogBoxW(hInst, addon->dialog_template, 0, installer_proc);