From 5093a48728b4aaa20fa1a16acff9f968099501f5 Mon Sep 17 00:00:00 2001
From: Anton Rudnev <mibori@builder.office.etersoft.ru>
Date: Tue, 27 Jan 2009 17:52:07 +0300
Subject: [PATCH] msi: Automatic path correction for custom action #50 (eterbug 1126)

---
 dlls/msi/custom.c |  146 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 143 insertions(+), 3 deletions(-)

diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 55d2bc7..00f50ed 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -1095,6 +1095,119 @@ static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source,
     return ERROR_FUNCTION_FAILED;
 }
 
+
+LPWSTR get_dirname_alternative(MSIPACKAGE *package, LPCWSTR name){
+    MSIQUERY *view = NULL;
+    static const WCHAR querystr[] =
+        {'S','E','L','E','C','T',' ','*',
+            ' ','F','R','O','M',' ','`','D','i','r','e','c','t','o','r','y','`', 0};
+    WCHAR *ret = NULL;
+    UINT r;
+    MSIRECORD *rec = NULL;
+
+    r = MSI_OpenQuery(package->db, &view, querystr);
+    MSI_ViewExecute(view, NULL);
+    do
+    {
+        WCHAR *val = NULL, *cur = NULL;
+        UINT i;
+        r = MSI_ViewFetch(view, &rec);
+
+        val = MSI_RecordGetString(rec, 3);
+
+        if(val == NULL)
+            continue;
+
+        for(cur = val, i = 0; !((*cur == '|') || (*cur == 0)); cur ++, i ++);
+        if(*cur == 0)
+            continue;
+
+        if((strlenW(name) == i) && (strncmpW(name, val, i) == 0))
+        {
+            ret = strdupW(cur + 1);
+            break;
+        }
+
+        if((strlenW(name) == strlenW(cur + 1)) && (strcmpW(name, cur + 1) == 0))
+        {
+            ret = lstrcpynW(msi_alloc((i + 1) * sizeof(WCHAR)), val, i + 1);
+            break;
+        }
+    }
+    while (r != ERROR_NO_MORE_ITEMS);
+
+    MSI_ViewClose(view);
+    msiobj_release(&view->hdr);
+    return ret;
+}
+
+LPWSTR correct_filepath_alternative(MSIPACKAGE *package, LPCWSTR filepath){
+    WCHAR
+        *first = filepath, *second = filepath,
+        *acc = NULL, *new_acc = NULL;
+    static const WCHAR pathcons[] = {'%','s','\\','%','s', 0};
+
+    for
+    (
+        first = filepath, second = filepath, acc = NULL;;
+        first = ++ second, acc = new_acc
+    )
+    {
+        WCHAR *symbol = NULL, *alt_symbol = NULL;
+
+        while(!((*second == 0) || (*second == '\\')))
+            second ++;
+
+        if(*second == 0)
+        {
+            WCHAR *msi_allocated
+                = msi_alloc(sizeof(WCHAR) * (strlenW(acc) + strlenW(first + 1) + 1));
+
+            sprintfW(msi_allocated, pathcons, acc, first);
+            new_acc = msi_allocated;
+
+            msi_free(acc);
+            break;
+        }
+
+        symbol = lstrcpynW(msi_alloc(sizeof(WCHAR) * (second - first)), first, second - first + 1);
+        alt_symbol = get_dirname_alternative(package, symbol);
+
+        if(alt_symbol)
+        {
+            if(acc)
+            {
+                WCHAR *msi_allocated =
+                    msi_alloc(sizeof(WCHAR) * (strlenW(acc) + strlenW(alt_symbol) + 2));
+
+                sprintfW(msi_allocated, pathcons, acc, alt_symbol);
+                new_acc = msi_allocated;
+            }
+            else
+                new_acc = strdupW(alt_symbol);
+
+            msi_free(alt_symbol);
+        }
+        else
+            if(acc)
+            {
+                WCHAR *msi_allocated =
+                    msi_alloc(sizeof(WCHAR) * (strlenW(acc) + strlenW(symbol) + 2));
+
+                sprintfW(msi_allocated, pathcons, acc, symbol);
+                new_acc = msi_allocated;
+            }
+            else
+                new_acc = strdupW(symbol);
+
+        msi_free(symbol);
+        if(acc)
+            msi_free(acc);
+    }
+
+    return new_acc;
+}
+
 static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
                                 LPCWSTR target, const INT type, LPCWSTR action)
 {
@@ -1126,10 +1239,7 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
     {
         strcatW(cmd,spc);
         strcatW(cmd,deformated);
-
-        msi_free(deformated);
     }
-    msi_free(prop);
 
     TRACE("executing exe %s\n", debugstr_w(cmd));
 
@@ -1138,8 +1248,38 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
 
     if ( !rc )
     {
+        WCHAR *corrected;
+
         ERR("Unable to execute command %s\n", debugstr_w(cmd));
+
+        /* automatic correction - eterbug-1126 */
         msi_free(cmd);
+        corrected = correct_filepath_alternative(package, prop);
+
+        /* new cmd */
+        len = strlenW(corrected) + 2;
+        if (deformated)
+            len += strlenW(deformated);
+        cmd = msi_alloc(sizeof(WCHAR) * len);
+        strcpyW(cmd, corrected);
+        if(deformated)
+        {
+            strcatW(cmd, spc);
+            strcatW(cmd, deformated);
+
+            msi_free(deformated);
+        }
+
+        rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
+                  c_collen, &si, &info);
+
+        if( !rc )
+            ERR("Invalid automatic correction (%s)\n", debugstr_w(cmd));
+
+        msi_free(cmd);
+        msi_free(prop);
+        msi_free(corrected);
+
         return ERROR_SUCCESS;
     }
     msi_free(cmd);
-- 
1.6.0.2.GIT

