Commit fca258ef authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

localspl: Add pipe port extension.

parent aa4e9c39
MODULE = localspl.dll
UNIXLIB = localspl.so
IMPORTS = spoolss user32 advapi32
EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \
cups.c \
localmon.c \
provider.c
......
/*
* 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(&params);
}
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(&params);
}
const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
{
wow64_start_doc,
wow64_write_doc,
end_doc,
};
#endif /* _WIN64 */
......@@ -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, &params);
}
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, &params);
*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, &params);
}
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;
......
......@@ -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__ */
......@@ -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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment