[PATCH 0/1] MR10760: wusa: Split cabinet path before calling FDICopy.
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. After applying this patch both native (from VistaSP1 and Win7SP1) and built-in cabinet.dll allow the graceful execution of wusa.exe -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10760
From: David Carrasco Flores <dcf1007@gmail.com> 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. After applying this patch both native (from VistaSP1 and Win7SP1) and built-in cabinet.dll allow the graceful execution of wusa.exe --- 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 ef7302847cc..20b0a21b540 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/10760
This merge request was approved by David Carrasco Flores. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10760
participants (2)
-
David Carrasco Flores -
David Carrasco Flores (@dcf1007)