From 9c1492069b1b1cba2a202cf1a29a240f92ebc828 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 17 Jan 2014 01:31:22 +0100 Subject: [PATCH] Add SRWLock patches and workarounds for shlwapi url functions. --- ...SRWLock-functions-using-keyed-events.patch | 207 ++++++++++++++++++ .../17545d49-1dfc-4294-bb30-2df2f29b0d95.def | 3 + ...additional-tests-for-UrlCombine-and-.patch | 126 +++++++++++ ...mbineW-workaround-for-relative-paths.patch | 44 ++++ .../e46b26df-3c1b-419c-9579-f0d1e1c50bea.def | 3 + patches/patch-list.patch | 4 +- 6 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 patches/08-SRWLock/0001-ntdll-Implement-SRWLock-functions-using-keyed-events.patch create mode 100644 patches/08-SRWLock/17545d49-1dfc-4294-bb30-2df2f29b0d95.def create mode 100644 patches/99-Workarounds/0001-shlwapi-tests-Add-additional-tests-for-UrlCombine-and-.patch create mode 100644 patches/99-Workarounds/0002-shlwapi-UrlCombineW-workaround-for-relative-paths.patch create mode 100644 patches/99-Workarounds/e46b26df-3c1b-419c-9579-f0d1e1c50bea.def diff --git a/patches/08-SRWLock/0001-ntdll-Implement-SRWLock-functions-using-keyed-events.patch b/patches/08-SRWLock/0001-ntdll-Implement-SRWLock-functions-using-keyed-events.patch new file mode 100644 index 00000000..6a20d1d1 --- /dev/null +++ b/patches/08-SRWLock/0001-ntdll-Implement-SRWLock-functions-using-keyed-events.patch @@ -0,0 +1,207 @@ +From 7324234ddce315b21a31e9e810593ea0c6917384 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sat, 11 Jan 2014 02:18:10 +0100 +Subject: ntdll: Implement SRWLock functions using keyed events + +--- + dlls/kernel32/tests/sync.c | 6 --- + dlls/ntdll/sync.c | 119 ++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 115 insertions(+), 10 deletions(-) + +diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c +index e5d1353..c7cceaa 100644 +--- a/dlls/kernel32/tests/sync.c ++++ b/dlls/kernel32/tests/sync.c +@@ -1890,9 +1890,6 @@ static void test_srwlock_base(void) + WaitForSingleObject(h2, 100); + WaitForSingleObject(h3, 100); + +- /* the current implementation just consists of stubs and all tests fail */ +- todo_wine +- { + ok(!srwlock_base_errors.wrong_execution_order, + "thread commands were executed in the wrong order (occurred %d times).\n", + srwlock_base_errors.wrong_execution_order); +@@ -1916,7 +1913,6 @@ static void test_srwlock_base(void) + ok(!srwlock_base_errors.excl_not_preferred, + "thread waiting for exclusive access to the SHMLock was not preferred (occurred %d times).\n", + srwlock_base_errors.excl_not_preferred); +- } + } + + static SRWLOCK srwlock_example; +@@ -1994,8 +1990,6 @@ static void test_srwlock_example(void) + WaitForSingleObject(h3, 1000); + + ok(!srwlock_inside, "threads didn't terminate properly, srwlock_inside is %d.\n", srwlock_inside); +- +- todo_wine + ok(!srwlock_example_errors, "errors occured while running SRWLock example test (number of errors: %d)\n", + srwlock_example_errors); + +diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c +index c94d9c4..d68be50 100644 +--- a/dlls/ntdll/sync.c ++++ b/dlls/ntdll/sync.c +@@ -1382,8 +1382,88 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu + return RtlRunOnceComplete( once, 0, context ? *context : NULL ); + } + ++#define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000 ++#define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000 ++#define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff ++#define SRWLOCK_RES_EXCLUSIVE 0x00010000 ++#define SRWLOCK_RES_SHARED 0x00000001 ++ ++#ifdef WORDS_BIGENDIAN ++#define srwlock_key_exclusive(lock) (&lock->Ptr) ++#define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2)) ++#else ++#define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2)) ++#define srwlock_key_shared(lock) (&lock->Ptr) ++#endif ++ ++static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr ) ++{ ++ unsigned int val, tmp; ++ /* Atomically modifies the value of *dest by adding incr. If the shared ++ * queue is empty and there are threads waiting for exclusive access, then ++ * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that ++ * they are allowed to use again the shared queue counter. */ ++ for (val = *dest;; val = tmp) ++ { ++ tmp = val + incr; ++ if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE)) ++ tmp |= SRWLOCK_MASK_IN_EXCLUSIVE; ++ if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val) ++ break; ++ } ++ return val; ++} ++ ++static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr ) ++{ ++ unsigned int val, tmp; ++ /* Atomically modifies the value of *dest by adding incr. If the queue of ++ * threads waiting for exclusive access is empty, then remove the ++ * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will ++ * remain). */ ++ for (val = *dest;; val = tmp) ++ { ++ tmp = val + incr; ++ if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE)) ++ tmp &= SRWLOCK_MASK_SHARED_QUEUE; ++ if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val) ++ break; ++ } ++ return val; ++} ++ ++static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val ) ++{ ++ /* Used when a thread leaves an exclusive section. If there are other ++ * exclusive access threads they are processed first, afterwards process ++ * the shared waiters. */ ++ if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) ++ NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL ); ++ else ++ { ++ val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */ ++ while (val--) ++ NtReleaseKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL ); ++ } ++} ++ ++static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val ) ++{ ++ /* Wake up one exclusive thread as soon as the last shared access thread ++ * has left. */ ++ if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE)) ++ NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL ); ++} ++ + /*********************************************************************** + * RtlInitializeSRWLock (NTDLL.@) ++ * ++ * NOTES ++ * Please note that SRWLocks do not keep track of the owner of a lock. ++ * It doesn't make any difference which thread for example unlocks an ++ * SRWLock (see corresponding tests). This implementation uses two ++ * keyed events (one for the exclusive waiters and one for the shared ++ * waiters) and is limited to 2^15-1 waiting threads. + */ + void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock ) + { +@@ -1392,10 +1472,16 @@ void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock ) + + /*********************************************************************** + * RtlAcquireSRWLockExclusive (NTDLL.@) ++ * ++ * NOTES ++ * Unlike RtlAcquireResourceExclusive this function doesn't allow ++ * nested calls from the same thread. "Upgrading" a shared access lock ++ * to an exclusive access lock also doesn't seem to be supported. + */ + void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) + { +- FIXME( "%p stub\n", lock ); ++ if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE )) ++ NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL ); + } + + /*********************************************************************** +@@ -1403,7 +1489,30 @@ void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) + */ + void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock ) + { +- FIXME( "%p stub\n", lock ); ++ unsigned int val, tmp; ++ /* Acquires a shared lock. If its currently not possible to add elements to ++ * the shared queue, then request exclusive access instead. */ ++ for (val = *(unsigned int *)&lock->Ptr;; val = tmp) ++ { ++ if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE)) ++ tmp = val + SRWLOCK_RES_EXCLUSIVE; ++ else ++ tmp = val + SRWLOCK_RES_SHARED; ++ if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val) ++ break; ++ } ++ ++ /* Drop exclusive access again and instead requeue for shared access. */ ++ if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE)) ++ { ++ NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL ); ++ val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED ++ - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE; ++ srwlock_leave_exclusive( lock, val ); ++ } ++ ++ if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) ++ NtWaitForKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL ); + } + + /*********************************************************************** +@@ -1411,7 +1520,8 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock ) + */ + void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock ) + { +- FIXME( "%p stub\n", lock ); ++ srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, ++ - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE ); + } + + /*********************************************************************** +@@ -1419,7 +1529,8 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock ) + */ + void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) + { +- FIXME( "%p stub\n", lock ); ++ srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, ++ - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED ); + } + + /*********************************************************************** +-- +1.7.9.5 + diff --git a/patches/08-SRWLock/17545d49-1dfc-4294-bb30-2df2f29b0d95.def b/patches/08-SRWLock/17545d49-1dfc-4294-bb30-2df2f29b0d95.def new file mode 100644 index 00000000..c3408963 --- /dev/null +++ b/patches/08-SRWLock/17545d49-1dfc-4294-bb30-2df2f29b0d95.def @@ -0,0 +1,3 @@ +Revision: 1 +Author: Sebastian Lackner +Title: Implementation of SRWLock functions. diff --git a/patches/99-Workarounds/0001-shlwapi-tests-Add-additional-tests-for-UrlCombine-and-.patch b/patches/99-Workarounds/0001-shlwapi-tests-Add-additional-tests-for-UrlCombine-and-.patch new file mode 100644 index 00000000..4c4b82e1 --- /dev/null +++ b/patches/99-Workarounds/0001-shlwapi-tests-Add-additional-tests-for-UrlCombine-and-.patch @@ -0,0 +1,126 @@ +From 549999ab13d6078b39210a467753e8b8dfff705e Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Fri, 17 Jan 2014 01:19:41 +0100 +Subject: shlwapi/tests: Add additional tests for UrlCombine and + UrlCanonicalize + +--- + dlls/shlwapi/tests/url.c | 46 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 36 insertions(+), 10 deletions(-) + +diff --git a/dlls/shlwapi/tests/url.c b/dlls/shlwapi/tests/url.c +index f53a545..ecbdfab 100644 +--- a/dlls/shlwapi/tests/url.c ++++ b/dlls/shlwapi/tests/url.c +@@ -195,7 +195,15 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { + {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_UNESCAPE, S_OK, "res://c:\\tests/res\\foo bar/strange\\sth", FALSE}, + {"A", 0, S_OK, "A", FALSE}, + {"../A", 0, S_OK, "../A", FALSE}, ++ {".\\A", 0, S_OK, ".\\A", FALSE}, ++ {"A\\.\\B", 0, S_OK, "A\\.\\B", FALSE}, + {"A/../B", 0, S_OK, "B", TRUE}, ++ {"A/../B/./../C", 0, S_OK, "C", TRUE}, ++ {"A/../B/./../C", URL_DONT_SIMPLIFY, S_OK, "A/../B/./../C", FALSE}, ++ {".", 0, S_OK, "/", TRUE}, ++ {"./A", 0, S_OK, "A", TRUE}, ++ {"A/./B", 0, S_OK, "A/B", TRUE}, ++ {"/:test\\", 0, S_OK, "/:test\\", TRUE}, + {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", FALSE} /*LimeWire online installer calls this*/, + {"http:www.winehq.org/dir/../index.html", 0, S_OK, "http:www.winehq.org/index.html"}, + {"http://localhost/test.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/test.html"}, +@@ -308,6 +316,7 @@ typedef struct _TEST_URL_COMBINE { + DWORD flags; + HRESULT expectret; + const char *expecturl; ++ BOOL todo; + } TEST_URL_COMBINE; + + static const TEST_URL_COMBINE TEST_COMBINE[] = { +@@ -329,6 +338,15 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { + {"http://www.winehq.org/test14#aaa/bbb#ccc", "#", 0, S_OK, "http://www.winehq.org/test14#"}, + {"http://www.winehq.org/tests/?query=x/y/z", "tests15", 0, S_OK, "http://www.winehq.org/tests/tests15"}, + {"http://www.winehq.org/tests/?query=x/y/z#example", "tests16", 0, S_OK, "http://www.winehq.org/tests/tests16"}, ++ {"http://www.winehq.org/tests17", ".", 0, S_OK, "http://www.winehq.org/", TRUE}, ++ {"http://www.winehq.org/tests18/test", ".", 0, S_OK, "http://www.winehq.org/tests18/", TRUE}, ++ {"http://www.winehq.org/tests19/test", "./", 0, S_OK, "http://www.winehq.org/tests19/", FALSE}, ++ {"http://www.winehq.org/tests20/test", "/", 0, S_OK, "http://www.winehq.org/", FALSE}, ++ {"http://www.winehq.org/tests/test", "./test21", 0, S_OK, "http://www.winehq.org/tests/test21", FALSE}, ++ {"http://www.winehq.org/tests/test", "./test22/../test", 0, S_OK, "http://www.winehq.org/tests/test", FALSE}, ++ {"http://www.winehq.org/tests/", "http://www.winehq.org:80/tests23", 0, S_OK, "http://www.winehq.org/tests23", TRUE}, ++ {"http://www.winehq.org/tests/", "tests24/./test/../test", 0, S_OK, "http://www.winehq.org/tests/tests24/test", FALSE}, ++ {"http://www.winehq.org/tests/./tests25", "./", 0, S_OK, "http://www.winehq.org/tests/", FALSE}, + {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"}, + {"file:///C:\\dir\\file.txt#hash\\hash", "test.txt", 0, S_OK, "file:///C:/dir/file.txt#hash/test.txt"}, + {"file:///C:\\dir\\file.html#hash\\hash", "test.html", 0, S_OK, "file:///C:/dir/test.html"}, +@@ -1077,7 +1095,7 @@ static void test_UrlCanonicalizeW(void) + + /* ########################### */ + +-static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl) ++static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl, BOOL todo) + { + HRESULT hr; + CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH]; +@@ -1102,34 +1120,42 @@ static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFla + dwSize = 0; + hr = pUrlCombineA(szUrl1, szUrl2, NULL, &dwSize, dwFlags); + ok(hr == E_POINTER, "Checking length of string, return was 0x%08x, expected 0x%08x\n", hr, E_POINTER); +- ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); ++ ok(todo || dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); + + dwSize--; + hr = pUrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags); + ok(hr == E_POINTER, "UrlCombineA returned 0x%08x, expected 0x%08x\n", hr, E_POINTER); +- ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); ++ ok(todo || dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); + + hr = pUrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags); + ok(hr == dwExpectReturn, "UrlCombineA returned 0x%08x, expected 0x%08x\n", hr, dwExpectReturn); +- ok(dwSize == dwExpectLen, "Got length %d, expected %d\n", dwSize, dwExpectLen); +- if(SUCCEEDED(hr)) { +- ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl); ++ ++ if (todo) ++ { ++ todo_wine ok(dwSize == dwExpectLen && (!SUCCEEDED(hr) || strcmp(szReturnUrl, szExpectUrl)==0), ++ "Expected %s (len=%d), but got %s (len=%d)\n", szExpectUrl, dwExpectLen, SUCCEEDED(hr) ? szReturnUrl : "(null)", dwSize); ++ } ++ else ++ { ++ ok(dwSize == dwExpectLen, "Got length %d, expected %d\n", dwSize, dwExpectLen); ++ if (SUCCEEDED(hr)) ++ ok(strcmp(szReturnUrl, szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl); + } + + if (pUrlCombineW) { + dwSize = 0; + hr = pUrlCombineW(wszUrl1, wszUrl2, NULL, &dwSize, dwFlags); + ok(hr == E_POINTER, "Checking length of string, return was 0x%08x, expected 0x%08x\n", hr, E_POINTER); +- ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); ++ ok(todo || dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); + + dwSize--; + hr = pUrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags); + ok(hr == E_POINTER, "UrlCombineW returned 0x%08x, expected 0x%08x\n", hr, E_POINTER); +- ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); ++ ok(todo || dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1); + + hr = pUrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags); + ok(hr == dwExpectReturn, "UrlCombineW returned 0x%08x, expected 0x%08x\n", hr, dwExpectReturn); +- ok(dwSize == dwExpectLen, "Got length %d, expected %d\n", dwSize, dwExpectLen); ++ ok(todo || dwSize == dwExpectLen, "Got length %d, expected %d\n", dwSize, dwExpectLen); + if(SUCCEEDED(hr)) { + wszConvertedUrl = GetWideString(szReturnUrl); + ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCombine!\n"); +@@ -1149,7 +1175,7 @@ static void test_UrlCombine(void) + unsigned int i; + for(i=0; i +Date: Fri, 17 Jan 2014 01:27:53 +0100 +Subject: shlwapi: UrlCombineW workaround for relative paths + +--- + dlls/shlwapi/tests/url.c | 4 ++-- + dlls/shlwapi/url.c | 5 ++++- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/dlls/shlwapi/tests/url.c b/dlls/shlwapi/tests/url.c +index ecbdfab..8a99f7e 100644 +--- a/dlls/shlwapi/tests/url.c ++++ b/dlls/shlwapi/tests/url.c +@@ -338,8 +338,8 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { + {"http://www.winehq.org/test14#aaa/bbb#ccc", "#", 0, S_OK, "http://www.winehq.org/test14#"}, + {"http://www.winehq.org/tests/?query=x/y/z", "tests15", 0, S_OK, "http://www.winehq.org/tests/tests15"}, + {"http://www.winehq.org/tests/?query=x/y/z#example", "tests16", 0, S_OK, "http://www.winehq.org/tests/tests16"}, +- {"http://www.winehq.org/tests17", ".", 0, S_OK, "http://www.winehq.org/", TRUE}, +- {"http://www.winehq.org/tests18/test", ".", 0, S_OK, "http://www.winehq.org/tests18/", TRUE}, ++ {"http://www.winehq.org/tests17", ".", 0, S_OK, "http://www.winehq.org/"}, ++ {"http://www.winehq.org/tests18/test", ".", 0, S_OK, "http://www.winehq.org/tests18/"}, + {"http://www.winehq.org/tests19/test", "./", 0, S_OK, "http://www.winehq.org/tests19/", FALSE}, + {"http://www.winehq.org/tests20/test", "/", 0, S_OK, "http://www.winehq.org/", FALSE}, + {"http://www.winehq.org/tests/test", "./test21", 0, S_OK, "http://www.winehq.org/tests/test21", FALSE}, +diff --git a/dlls/shlwapi/url.c b/dlls/shlwapi/url.c +index 11589e4..58eb87c 100644 +--- a/dlls/shlwapi/url.c ++++ b/dlls/shlwapi/url.c +@@ -914,7 +914,10 @@ HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, + work = preliminary + base.cchProtocol+1+base.cchSuffix - 1; + if (*work++ != '/') + *(work++) = '/'; +- strcpyW(work, relative.pszSuffix); ++ if (relative.pszSuffix[0] == '.' && relative.pszSuffix[1] == 0) ++ *work = 0; ++ else ++ strcpyW(work, relative.pszSuffix); + break; + + default: +-- +1.7.9.5 + diff --git a/patches/99-Workarounds/e46b26df-3c1b-419c-9579-f0d1e1c50bea.def b/patches/99-Workarounds/e46b26df-3c1b-419c-9579-f0d1e1c50bea.def new file mode 100644 index 00000000..3a10ddf3 --- /dev/null +++ b/patches/99-Workarounds/e46b26df-3c1b-419c-9579-f0d1e1c50bea.def @@ -0,0 +1,3 @@ +Revision: 1 +Author: Sebastian Lackner +Title: Workaround for broken implementation of shlwapi url functions. diff --git a/patches/patch-list.patch b/patches/patch-list.patch index b3c37320..67dd6ff5 100644 --- a/patches/patch-list.patch +++ b/patches/patch-list.patch @@ -33,7 +33,7 @@ diff --git a/libs/wine/config.c b/libs/wine/config.c index a273502..5fa0cd5 100644 --- a/libs/wine/config.c +++ b/libs/wine/config.c -@@ -478,6 +478,32 @@ const char *wine_get_version(void) +@@ -478,6 +478,34 @@ const char *wine_get_version(void) return PACKAGE_VERSION; } @@ -50,10 +50,12 @@ index a273502..5fa0cd5 100644 + { "cbe240e8-2c58-430a-b61c-7fbb9d0e1e11:1", "Sebastian Lackner", "Change return value of stub SetNamedPipeHandleState to TRUE." }, + { "00273da7-72f8-4025-9e96-0c2bc95dacdb:2", "Maarten Lankhorst", "Winepulse patches extracted from https://launchpad.net/~mlankhorst/+archive/ppa/+files/wine1.7_1.7.10-0ubuntu1~saucy1.debian.tar.gz." }, + { "29b2af38-7edd-11e3-a08d-0090f5c75ad5:1", "Erich E. Hoover", "Add support for security access parameters for named pipes." }, ++ { "17545d49-1dfc-4294-bb30-2df2f29b0d95:1", "Sebastian Lackner", "Implementation of SRWLock functions." }, + { "0b21d7ac-0387-4493-aa38-fbafe3e749f5:1", "Michael Müller", "Decrease minimum SetTimer interval from 15 to 5 ms." }, + { "19835498-8d90-4673-867e-2376af4d7c76:1", "Sebastian Lackner", "Allow to set wined3d strictDrawOrdering via environment variable." }, + { "59bd38b7-bbdc-4cfd-9ccd-1c72c4ed84c0:1", "Sebastian Lackner", "Implement X11DRV_FLUSH_GDI_DISPLAY ExtEscape command." }, + { "eec5dea8-879d-417b-9f97-364deaae6576:1", "Sebastian Lackner", "Add tests for IVMRMonitorConfig." }, ++ { "e46b26df-3c1b-419c-9579-f0d1e1c50bea:1", "Sebastian Lackner", "Workaround for broken implementation of shlwapi url functions." }, + { NULL, NULL, NULL } +}; +