[PATCH v2 0/2] MR10748: wusa: Recognize runtime.syswow64 expressions.
Some update manifests use $(runtime.syswow64) as an explicit target for the 32-bit system directory. wusa currently handles runtime.system32 with WoW64-aware redirection, but does not recognize runtime.syswow64, causing expression expansion to fail. Map runtime.syswow64 to CSIDL_SYSTEMX86 on x86_64, matching the existing runtime.programfilesx86 and runtime.commonfilesx86 handling. -- v2: wusa: Split cabinet path before calling FDICopy. https://gitlab.winehq.org/wine/wine/-/merge_requests/10748
From: David Carrasco Flores <dcf1007@gmail.com> Some update manifests use $(runtime.syswow64) as an explicit target for the 32-bit system directory. wusa currently handles runtime.system32 with WoW64-aware redirection, but does not recognize runtime.syswow64, causing expression expansion to fail. Map runtime.syswow64 to CSIDL_SYSTEMX86 on x86_64, matching the existing runtime.programfilesx86 and runtime.commonfilesx86 handling. --- programs/wusa/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/wusa/main.c b/programs/wusa/main.c index ef7302847cc..26e83e4fc20 100644 --- a/programs/wusa/main.c +++ b/programs/wusa/main.c @@ -507,6 +507,7 @@ static WCHAR *lookup_expression(struct assembly_entry *assembly, const WCHAR *ke else csidl = CSIDL_PROGRAM_FILES_COMMON; } #ifdef __x86_64__ + else if (!wcsicmp(key, L"runtime.syswow64")) csidl = CSIDL_SYSTEMX86; else if (!wcsicmp(key, L"runtime.programfilesx86")) csidl = CSIDL_PROGRAM_FILESX86; else if (!wcsicmp(key, L"runtime.commonfilesx86")) csidl = CSIDL_PROGRAM_FILES_COMMONX86; #endif -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10748
From: David Carrasco Flores <dcf1007@gmail.com> Wine's wusa currently passes the full cabinet path as the `pszCabinet` argument to `FDICopy()` and passes `NULL` as `pszCabPath`. This works with Wine's builtin cabinet implementation, but it does not match the documented FDICopy parameter usage. `FDICopy()` expects `pszCabinet` to contain only the cabinet file name, while `pszCabPath` contains the directory path. Wine's own FDICopy API documentation follows that convention, describing `pszCabinet` as the cabinet filename and `pszCabPath` as the cabinet file path. Microsoft's FDI documentation is more explicit: `pszCabinet` is the cabinet file name excluding path information, and `pszCabPath` is the cabinet path excluding the file name. The full cabinet path is then constructed internally by appending `pszCabinet` to `pszCabPath`. `pszCabPath` is an input `LPSTR` parameter and is not documented as optional. Passing `NULL` is therefore outside the documented API behavior, even though Wine's builtin cabinet.dll currently tolerates it. Native cabinet.dll crashes in this context. These changes are based on the existing path-splitting pattern used by `SetupIterateCabinetA()` in `dlls/setupapi/setupcab.c`, as well as the FDI resource-handling pattern used by `extract_cabinet()` in `dlls/msi/media.c`: - resolve the input path with `GetFullPathNameA()`; - split the result into `pszCabPath` and `pszCabinet`; - pass both values separately to `FDICopy()`; - release allocated memory on failure paths; - destroy the FDI context after `FDICopy()`, regardless of whether extraction succeeds. This improves compatibility with native cabinet.dll, which does not tolerate passing `NULL` for `pszCabPath` in this context. --- programs/wusa/main.c | 51 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/programs/wusa/main.c b/programs/wusa/main.c index 26e83e4fc20..31d44882011 100644 --- a/programs/wusa/main.c +++ b/programs/wusa/main.c @@ -246,18 +246,61 @@ static INT_PTR CDECL cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION static BOOL extract_cabinet(const WCHAR *filename, const WCHAR *destination) { char *filenameA = NULL; + CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *filepart = NULL; + DWORD fpnsize; BOOL ret = FALSE; HFDI hfdi; ERF erf; + if (!(filenameA = strdupWtoA(filename))) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (strlen(filenameA) >= MAX_PATH) + { + SetLastError(ERROR_BAD_PATHNAME); + free(filenameA); + return FALSE; + } + + fpnsize = GetFullPathNameA(filenameA, MAX_PATH, pszCabPath, &filepart); + + if (!fpnsize || fpnsize > MAX_PATH) + { + SetLastError(ERROR_BAD_PATHNAME); + free(filenameA); + return FALSE; + } + + if (filepart) + { + strcpy(pszCabinet, filepart); + *filepart = '\0'; + } + else + { + strcpy(pszCabinet, filenameA); + pszCabPath[0] = '\0'; + } + + free(filenameA); + + TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet)); + hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read, cabinet_write, cabinet_close, cabinet_seek, 0, &erf); - if (!hfdi) return FALSE; + if (!hfdi) + { + ERR("FDICreate failed\n"); + return FALSE; + } - if ((filenameA = strdupWtoA(filename))) + ret = FDICopy(hfdi, pszCabinet, pszCabPath, 0, cabinet_notify, NULL, (void *)destination); + if (!ret) { - ret = FDICopy(hfdi, filenameA, NULL, 0, cabinet_notify, NULL, (void *)destination); - free(filenameA); + ERR("FDICopy failed\n"); } FDIDestroy(hfdi); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10748
Please don't add more commits after the MR has been approved, instead start a new MR for further changes. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10748#note_137837
On Mon Apr 27 20:13:52 2026 +0000, Alexandre Julliard wrote:
Please don't add more commits after the MR has been approved, instead start a new MR for further changes. This was really an accident. I realized after commiting the changes. I can revert them and open a new MR if needed. I am very sorry.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10748#note_137838
On Mon Apr 27 20:13:52 2026 +0000, David Carrasco Flores wrote:
This was really an accident. I realized after commiting the changes. I can revert them and open a new MR if needed. I am very sorry. No worry, but yes, please revert this MR and open a new one.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10748#note_137839
participants (3)
-
Alexandre Julliard (@julliard) -
David Carrasco Flores -
David Carrasco Flores (@dcf1007)