From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/Makefile.in | 2 + dlls/localspl/cups.c | 227 +++++++++++++++++++++++++++++++ dlls/localspl/localmon.c | 59 ++++++-- dlls/localspl/localspl_private.h | 29 ++++ dlls/localspl/provider.c | 4 + 5 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 dlls/localspl/cups.c
diff --git a/dlls/localspl/Makefile.in b/dlls/localspl/Makefile.in index ab1d5a79d64..61ca097d9e4 100644 --- a/dlls/localspl/Makefile.in +++ b/dlls/localspl/Makefile.in @@ -1,9 +1,11 @@ MODULE = localspl.dll +UNIXLIB = localspl.so IMPORTS = spoolss user32 advapi32
EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \ + cups.c \ localmon.c \ provider.c
diff --git a/dlls/localspl/cups.c b/dlls/localspl/cups.c new file mode 100644 index 00000000000..25c485e220e --- /dev/null +++ b/dlls/localspl/cups.c @@ -0,0 +1,227 @@ +/* + * CUPS functions + * + * Copyright 2021 Huw Davies + * Copyright 2022 Piotr Caban + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "wine/debug.h" + +#include "localspl_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(localspl); + +typedef struct _doc_t +{ + BOOL (*write_doc)(struct _doc_t *, const BYTE *buf, unsigned int size); + BOOL (*end_doc)(struct _doc_t *); + + union + { + struct + { + pid_t pid; + int fd; + } pipe; + }; +} doc_t; + +static BOOL pipe_write_doc(doc_t *doc, const BYTE *buf, unsigned int size) +{ + return write(doc->pipe.fd, buf, size) == size; +} + +static BOOL pipe_end_doc(doc_t *doc) +{ + pid_t wret; + int status; + + close(doc->pipe.fd); + + do { + wret = waitpid(doc->pipe.pid, &status, 0); + } while (wret < 0 && errno == EINTR); + if (wret < 0) + { + ERR("waitpid() failed!\n"); + return FALSE; + } + if (!WIFEXITED(status) || WEXITSTATUS(status)) + { + ERR("child process failed! %d\n", status); + return FALSE; + } + + return TRUE; +} + +static BOOL pipe_start_doc(doc_t *doc, const WCHAR *cmd) +{ + char *cmdA; + int fds[2]; + DWORD len; + + doc->write_doc = pipe_write_doc; + doc->end_doc = pipe_end_doc; + + len = wcslen(cmd); + cmdA = malloc(len * 3 + 1); + ntdll_wcstoumbs(cmd, len + 1, cmdA, len * 3 + 1, FALSE); + + TRACE("printing with: %s\n", cmdA); + + if (pipe(fds)) + { + ERR("pipe() failed!\n"); + free(cmdA); + return FALSE; + } + + if ((doc->pipe.pid = fork()) == 0) + { + close(0); + dup2(fds[0], 0); + close(fds[1]); + + /* reset signals that we previously set to SIG_IGN */ + signal(SIGPIPE, SIG_DFL); + + execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL); + _exit(1); + } + close(fds[0]); + free(cmdA); + if (doc->pipe.pid == -1) + { + ERR("fork() failed!\n"); + close(fds[1]); + return FALSE; + } + + doc->pipe.fd = fds[1]; + return TRUE; +} + +static NTSTATUS start_doc(void *args) +{ + const struct start_doc_params *params = args; + doc_t *doc = malloc(sizeof(*doc)); + BOOL ret = FALSE; + + if (!doc) return STATUS_NO_MEMORY; + + if (params->type == PORT_IS_PIPE) + ret = pipe_start_doc(doc, params->port + 1 /* strlen("|") */); + + if (ret) + *params->doc = (size_t)doc; + else + free(doc); + return ret; +} + +static NTSTATUS write_doc(void *args) +{ + const struct write_doc_params *params = args; + doc_t *doc = (doc_t *)(size_t)params->doc; + + return doc->write_doc(doc, params->buf, params->size); +} + +static NTSTATUS end_doc(void *args) +{ + const struct end_doc_params *params = args; + doc_t *doc = (doc_t *)(size_t)params->doc; + NTSTATUS ret; + + ret = doc->end_doc(doc); + free(doc); + return ret; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = +{ + start_doc, + write_doc, + end_doc, +}; + +#ifdef _WIN64 + +typedef ULONG PTR32; + +static NTSTATUS wow64_start_doc(void *args) +{ + struct + { + unsigned int type; + const PTR32 port; + INT64 *doc; + } const *params32 = args; + + struct start_doc_params params = + { + params32->type, + ULongToPtr(params32->port), + params32->doc, + }; + + return start_doc(¶ms); +} + +static NTSTATUS wow64_write_doc(void *args) +{ + struct + { + INT64 doc; + const PTR32 buf; + unsigned int size; + } const *params32 = args; + + struct write_doc_params params = + { + params32->doc, + ULongToPtr(params32->buf), + params32->size, + }; + + return write_doc(¶ms); +} + +const unixlib_entry_t __wine_unix_call_wow64_funcs[] = +{ + wow64_start_doc, + wow64_write_doc, + end_doc, +}; + +#endif /* _WIN64 */ diff --git a/dlls/localspl/localmon.c b/dlls/localspl/localmon.c index 43e6197fa47..9f403b9e85e 100644 --- a/dlls/localspl/localmon.c +++ b/dlls/localspl/localmon.c @@ -66,6 +66,7 @@ typedef struct { struct list entry; DWORD type; HANDLE hfile; + INT64 doc_handle; WCHAR nameW[1]; } port_t;
@@ -95,7 +96,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hinstDLL ); localspl_instance = hinstDLL; - break; + return !__wine_init_unix_call(); } return TRUE; } @@ -249,7 +250,7 @@ getports_cleanup: * */
-static DWORD get_type_from_name(LPCWSTR name) +static DWORD get_type_from_name(LPCWSTR name, BOOL check_filename) { HANDLE hfile;
@@ -274,6 +275,9 @@ static DWORD get_type_from_name(LPCWSTR name) if (!wcsncmp(name, L"LPR:", ARRAY_SIZE(L"LPR:") - 1)) return PORT_IS_LPR;
+ if (!check_filename) + return PORT_IS_UNKNOWN; + /* Must be a file or a directory. Does the file exist ? */ hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name)); @@ -301,9 +305,12 @@ static DWORD get_type_from_local_name(LPCWSTR nameW) LPWSTR myname = NULL; DWORD needed = 0; DWORD numentries = 0; - DWORD id = 0; + DWORD id;
- TRACE("(%s)\n", debugstr_w(myname)); + TRACE("(%s)\n", debugstr_w(nameW)); + + if ((id = get_type_from_name(nameW, FALSE)) >= PORT_IS_WINE) + return id;
needed = get_ports_from_reg(1, NULL, 0, &numentries); pi = malloc(needed); @@ -313,17 +320,17 @@ static DWORD get_type_from_local_name(LPCWSTR nameW) if (pi && needed && numentries > 0) { /* we got a number of valid ports. */
- while ((myname == NULL) && (id < numentries)) + for (id = 0; id < numentries; id++) { if (lstrcmpiW(nameW, pi[id].pName) == 0) { TRACE("(%lu) found %s\n", id, debugstr_w(pi[id].pName)); myname = pi[id].pName; + break; } - id++; } }
- id = (myname) ? get_type_from_name(myname) : PORT_IS_UNKNOWN; + id = myname ? get_type_from_name(myname, TRUE) : PORT_IS_UNKNOWN;
free(pi); return id; @@ -478,6 +485,7 @@ static BOOL WINAPI localmon_OpenPortW(LPWSTR pName, PHANDLE phPort)
port->type = type; port->hfile = INVALID_HANDLE_VALUE; + port->doc_handle = 0; lstrcpyW(port->nameW, pName); *phPort = port;
@@ -498,6 +506,19 @@ static BOOL WINAPI localmon_StartDocPort(HANDLE hport, WCHAR *printer_name, TRACE("(%p %s %ld %ld %p)\n", hport, debugstr_w(printer_name), job_id, level, doc_info);
+ if (port->type == PORT_IS_PIPE) + { + struct start_doc_params params; + + if (port->doc_handle) + return TRUE; + + params.type = port->type; + params.port = port->nameW; + params.doc = &port->doc_handle; + return UNIX_CALL(start_doc, ¶ms); + } + if (port->type != PORT_IS_FILE) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); @@ -525,6 +546,19 @@ static BOOL WINAPI localmon_WritePort(HANDLE hport, BYTE *buf, DWORD size,
TRACE("(%p %p %lu %p)\n", hport, buf, size, written);
+ if (port->type == PORT_IS_PIPE) + { + struct write_doc_params params; + BOOL ret; + + params.doc = port->doc_handle; + params.buf = buf; + params.size = size; + ret = UNIX_CALL(write_doc, ¶ms); + *written = ret ? size : 0; + return ret; + } + return WriteFile(port->hfile, buf, size, written, NULL); }
@@ -534,6 +568,15 @@ static BOOL WINAPI localmon_EndDocPort(HANDLE hport)
TRACE("(%p)\n", hport);
+ if (port->type == PORT_IS_PIPE) + { + struct end_doc_params params; + + params.doc = port->doc_handle; + port->doc_handle = 0; + return UNIX_CALL(end_doc, ¶ms); + } + CloseHandle(port->hfile); port->hfile = INVALID_HANDLE_VALUE; return TRUE; @@ -712,7 +755,7 @@ static DWORD WINAPI localmon_XcvDataPort(HANDLE hXcv, LPCWSTR pszDataName, PBYTE
if (!lstrcmpW(pszDataName, L"PortIsValid")) { TRACE("InputData (%ld): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData)); - res = get_type_from_name((LPCWSTR) pInputData); + res = get_type_from_name((LPCWSTR) pInputData, TRUE); TRACE("detected as %lu\n", res); /* names, that we have recognized, are valid */ if (res) return ERROR_SUCCESS; diff --git a/dlls/localspl/localspl_private.h b/dlls/localspl/localspl_private.h index b82dfa2dedf..b76071f049a 100644 --- a/dlls/localspl/localspl_private.h +++ b/dlls/localspl/localspl_private.h @@ -22,6 +22,8 @@ #define __WINE_LOCALSPL_PRIVATE__
#include <windef.h> +#include "winternl.h" +#include "wine/unixlib.h"
extern HINSTANCE localspl_instance DECLSPEC_HIDDEN;
@@ -165,5 +167,32 @@ extern HINSTANCE localspl_instance DECLSPEC_HIDDEN; #define PORT_IS_CUPS 7 #define PORT_IS_LPR 8
+struct start_doc_params +{ + unsigned int type; + const WCHAR *port; + INT64 *doc; +}; + +struct write_doc_params +{ + INT64 doc; + const BYTE *buf; + unsigned int size; +}; + +struct end_doc_params +{ + INT64 doc; +}; + +#define UNIX_CALL(func, params) WINE_UNIX_CALL(unix_ ## func, params) + +enum cups_funcs +{ + unix_start_doc, + unix_write_doc, + unix_end_doc, +};
#endif /* __WINE_LOCALSPL_PRIVATE__ */ diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index f34653291c1..e79d8f23350 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -987,6 +987,10 @@ static monitor_t * monitor_load_by_port(LPCWSTR portname)
TRACE("(%s)\n", debugstr_w(portname));
+ /* wine specific ports */ + if (portname[0] == '|') + return monitor_load(L"Local Port", NULL); + /* Try the Local Monitor first */ if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) { if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {