Initial commit based on upstream Wine 1.7.6.

This commit is contained in:
Erich E. Hoover
2013-11-21 13:33:37 -07:00
parent ecd8abd770
commit 6106549adc
25 changed files with 2847 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
From c1f305f001257ac6bc215abd34c1577e7d9bf7f2 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 4 Oct 2013 08:10:20 -0600
Subject: ws2_32: Ask the server to process unsupported WSAIoctl operations.
---
dlls/ws2_32/socket.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 679258b..44a9093 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -3608,6 +3608,36 @@ static const char *debugstr_wsaioctl(DWORD ioctl)
(USHORT)(ioctl & 0xffff));
}
+/* do an ioctl call through the server */
+static DWORD server_ioctl_sock( SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size,
+ LPVOID out_buff, DWORD out_size, LPDWORD ret_size,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion )
+{
+ HANDLE event = overlapped ? overlapped->hEvent : 0;
+ HANDLE handle = SOCKET2HANDLE( s );
+ struct ws2_async *wsa;
+ NTSTATUS status;
+ PIO_STATUS_BLOCK io;
+
+ if (!(wsa = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wsa) )))
+ return WSA_NOT_ENOUGH_MEMORY;
+ wsa->hSocket = handle;
+ wsa->user_overlapped = overlapped;
+ wsa->completion_func = completion;
+ io = (overlapped ? (PIO_STATUS_BLOCK)overlapped : &wsa->local_iosb);
+
+ status = NtDeviceIoControlFile( handle, event, (PIO_APC_ROUTINE)ws2_async_apc, wsa, io, code,
+ in_buff, in_size, out_buff, out_size );
+ if (status == STATUS_NOT_SUPPORTED)
+ FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
+ code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
+
+ if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, wsa );
+
+ return NtStatusToWSAError( status );
+}
+
/**********************************************************************
* WSAIoctl (WS2_32.50)
*
@@ -3800,9 +3830,8 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
}
case WS_SIO_ADDRESS_LIST_CHANGE:
- FIXME("-> SIO_ADDRESS_LIST_CHANGE request: stub\n");
- /* FIXME: error and return code depend on whether socket was created
- * with WSA_FLAG_OVERLAPPED, but there is no easy way to get this */
+ TRACE("-> SIO_ADDRESS_LIST_CHANGE request\n");
+ status = WSAEOPNOTSUPP; /* this operation needs to be handled by the server */
break;
case WS_SIO_ADDRESS_LIST_QUERY:
@@ -4045,6 +4074,18 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
break;
}
+ if (status == WSAEOPNOTSUPP)
+ {
+ status = server_ioctl_sock(s, code, in_buff, in_size, out_buff, out_size, ret_size,
+ overlapped, completion);
+ if (status != WSAEOPNOTSUPP)
+ {
+ /* overlapped and completion operations will be handled by the server */
+ completion = NULL;
+ overlapped = NULL;
+ }
+ }
+
if (completion)
{
FIXME( "completion routine %p not supported\n", completion );
--
1.7.9.5

View File

@@ -0,0 +1,458 @@
From d90c33b813316c9fb409f835dbf55a5d42750200 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 4 Oct 2013 08:22:17 -0600
Subject: server: Implement an interface change notification object.
---
configure.ac | 2 +
server/event.c | 13 +++
server/named_pipe.c | 13 ---
server/object.h | 1 +
server/sock.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 306 insertions(+), 15 deletions(-)
diff --git a/configure.ac b/configure.ac
index fc68e1d..6db7859 100644
--- a/configure.ac
+++ b/configure.ac
@@ -429,7 +429,9 @@ AC_CHECK_HEADERS(\
linux/ioctl.h \
linux/joystick.h \
linux/major.h \
+ linux/netlink.h \
linux/param.h \
+ linux/rtnetlink.h \
linux/serial.h \
linux/types.h \
linux/ucdrom.h \
diff --git a/server/event.c b/server/event.c
index b8515af..e8a3888 100644
--- a/server/event.c
+++ b/server/event.c
@@ -124,6 +124,19 @@ struct event *create_event( struct directory *root, const struct unicode_str *na
return event;
}
+obj_handle_t alloc_wait_event( struct process *process )
+{
+ obj_handle_t handle = 0;
+ struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
+
+ if (event)
+ {
+ handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
+ release_object( event );
+ }
+ return handle;
+}
+
struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access )
{
return (struct event *)get_handle_obj( process, handle, access, &event_ops );
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 4c85104..6ba2145 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -587,19 +587,6 @@ static enum server_fd_type pipe_client_get_fd_type( struct fd *fd )
return FD_TYPE_PIPE;
}
-static obj_handle_t alloc_wait_event( struct process *process )
-{
- obj_handle_t handle = 0;
- struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
-
- if (event)
- {
- handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
- release_object( event );
- }
- return handle;
-}
-
static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
int blocking, const void *data, data_size_t size )
{
diff --git a/server/object.h b/server/object.h
index bb3ff21..bad162f 100644
--- a/server/object.h
+++ b/server/object.h
@@ -159,6 +159,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_
const struct security_descriptor *sd );
extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd );
+extern obj_handle_t alloc_wait_event( struct process *process );
extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern struct keyed_event *get_keyed_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern void pulse_event( struct event *event );
diff --git a/server/sock.c b/server/sock.c
index 1a3a8f7..c617928 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -44,11 +44,20 @@
#include <time.h>
#include <unistd.h>
+#ifdef HAVE_LINUX_NETLINK_H
+# include <linux/netlink.h>
+#endif
+#ifdef HAVE_LINUX_RTNETLINK_H
+# include <linux/rtnetlink.h>
+#endif
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "winerror.h"
+#define USE_WS_PREFIX
+#include "winsock2.h"
#include "process.h"
#include "file.h"
@@ -107,8 +116,12 @@ struct sock
struct sock *deferred; /* socket that waits for a deferred accept */
struct async_queue *read_q; /* queue for asynchronous reads */
struct async_queue *write_q; /* queue for asynchronous writes */
+ struct async_queue *ifchange_q; /* queue for interface change notifications */
+ struct list ifchange_entry; /* entry in ifchange notification list */
};
+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data );
+
static void sock_dump( struct object *obj, int verbose );
static int sock_signaled( struct object *obj, struct wait_queue_entry *entry );
static struct fd *sock_get_fd( struct object *obj );
@@ -117,6 +130,8 @@ static void sock_destroy( struct object *obj );
static int sock_get_poll_events( struct fd *fd );
static void sock_poll_event( struct fd *fd, int event );
static enum server_fd_type sock_get_fd_type( struct fd *fd );
+static obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+ int blocking, const void *data, data_size_t size );
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb );
@@ -151,12 +166,15 @@ static const struct fd_ops sock_fd_ops =
sock_poll_event, /* poll_event */
no_flush, /* flush */
sock_get_fd_type, /* get_fd_type */
- default_fd_ioctl, /* ioctl */
+ sock_ioctl, /* ioctl */
sock_queue_async, /* queue_async */
sock_reselect_async, /* reselect_async */
sock_cancel_async /* cancel_async */
};
+/* only keep one ifchange object around, all sockets waiting for wakeups will look to it */
+static struct object *ifchange_object = NULL;
+
/* Permutation of 0..FD_MAX_EVENTS - 1 representing the order in which
* we post messages if there are multiple events. Used to send
@@ -518,6 +536,39 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd )
return FD_TYPE_SOCKET;
}
+obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
+ int blocking, const void *data, data_size_t size )
+{
+ struct sock *sock = get_fd_user( fd );
+ obj_handle_t wait_handle = 0;
+ async_data_t new_data;
+
+ assert( sock->obj.ops == &sock_ops );
+
+ if (blocking)
+ {
+ if (!(wait_handle = alloc_wait_event( current->process ))) return 0;
+ new_data = *async_data;
+ new_data.event = wait_handle;
+ async_data = &new_data;
+ }
+ switch(code)
+ {
+ case WS_SIO_ADDRESS_LIST_CHANGE:
+ if (sock_add_ifchange( sock, async_data ))
+ {
+ set_error( STATUS_PENDING );
+ return wait_handle;
+ }
+ break;
+ default:
+ close_handle( current->process, wait_handle );
+ return default_fd_ioctl(fd, code, async_data, blocking, data, size);
+ }
+ close_handle( current->process, wait_handle );
+ return 0;
+}
+
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
{
struct sock *sock = get_fd_user( fd );
@@ -587,11 +638,17 @@ static void sock_destroy( struct object *obj )
/* FIXME: special socket shutdown stuff? */
- if ( sock->deferred )
+ if (sock->deferred)
release_object( sock->deferred );
free_async_queue( sock->read_q );
free_async_queue( sock->write_q );
+ if (sock->ifchange_q)
+ {
+ free_async_queue( sock->ifchange_q );
+ list_remove( &sock->ifchange_entry );
+ release_object( ifchange_object );
+ }
if (sock->event) release_object( sock->event );
if (sock->fd)
{
@@ -618,6 +675,7 @@ static void init_sock(struct sock *sock)
sock->deferred = NULL;
sock->read_q = NULL;
sock->write_q = NULL;
+ sock->ifchange_q = NULL;
memset( sock->errors, 0, sizeof(sock->errors) );
}
@@ -906,6 +964,236 @@ static void sock_set_error(void)
set_error( sock_get_ntstatus( errno ) );
}
+static void ifchange_dump( struct object *obj, int verbose );
+static struct fd *ifchange_get_fd( struct object *obj );
+static void ifchange_destroy( struct object *obj );
+
+static int ifchange_get_poll_events( struct fd *fd );
+static void ifchange_poll_event( struct fd *fd, int event );
+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue );
+
+struct ifchange
+{
+ struct object obj; /* object header */
+ struct fd *fd; /* interface change file descriptor */
+ struct list sockets; /* list of sockets to send interface change notifications */
+};
+
+static const struct object_ops ifchange_ops =
+{
+ sizeof(struct ifchange), /* size */
+ ifchange_dump, /* dump */
+ no_get_type, /* get_type */
+ add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ no_satisfied, /* satisfied */
+ no_signal, /* signal */
+ ifchange_get_fd, /* get_fd */
+ default_fd_map_access, /* map_access */
+ default_get_sd, /* get_sd */
+ default_set_sd, /* set_sd */
+ no_lookup_name, /* lookup_name */
+ no_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ ifchange_destroy /* destroy */
+};
+
+static const struct fd_ops ifchange_fd_ops =
+{
+ ifchange_get_poll_events, /* get_poll_events */
+ ifchange_poll_event, /* poll_event */
+ NULL, /* flush */
+ NULL, /* get_fd_type */
+ NULL, /* ioctl */
+ NULL, /* queue_async */
+ ifchange_reselect_async, /* reselect_async */
+ NULL /* cancel_async */
+};
+
+static int init_ifchange( struct ifchange *ifchange )
+{
+#if defined(NETLINK_ROUTE)
+ struct sockaddr_nl addr;
+ int unix_fd;
+
+ list_init( &ifchange->sockets );
+ unix_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
+ if (unix_fd == -1)
+ {
+ sock_set_error();
+ return 0;
+ }
+ fcntl( unix_fd, F_SETFL, O_NONBLOCK ); /* make socket nonblocking */
+ memset( &addr, 0, sizeof(addr) );
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = RTMGRP_IPV4_IFADDR;
+ /* bind the socket to the special netlink kernel interface */
+ if (bind( unix_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1)
+ {
+ sock_set_error();
+ close( unix_fd );
+ return 0;
+ }
+ if (!(ifchange->fd = create_anonymous_fd( &ifchange_fd_ops, unix_fd, &ifchange->obj, 0 )))
+ {
+ close( unix_fd );
+ return 0;
+ }
+ /* enable read wakeup on the file descriptor */
+ set_fd_events( ifchange->fd, POLLIN );
+ return 1;
+#else
+ fprintf(stderr, "Interface change notification is not supported on this platform.\n");
+ set_error( STATUS_NOT_SUPPORTED );
+ return 0;
+#endif
+}
+
+/* create a new ifchange notifier or, if one already exists, reuse the existing one */
+static struct object *create_ifchange( void )
+{
+ struct ifchange *ifchange;
+
+ /* we only need one of these interface notification objects, all of the sockets dependent upon
+ * it will wake up when a notification event occurs */
+ if (ifchange_object)
+ return grab_object( ifchange_object );
+ if (!(ifchange = alloc_object( &ifchange_ops )))
+ return NULL;
+ if (!init_ifchange( ifchange ))
+ {
+ release_object( ifchange );
+ return NULL;
+ }
+ ifchange_object = &ifchange->obj;
+ return ifchange_object;
+}
+
+/* add a socket to the interface change notification's list of sockets */
+void ifchange_add_sock( struct object *obj, struct sock *sock )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+
+ list_add_tail( &ifchange->sockets, &sock->ifchange_entry );
+}
+
+/* wake up an ifchange notification queue for a socket and decrement the ifchange object refcount */
+void sock_ifchange_wake_up( struct sock *sock, unsigned int status )
+{
+ assert( sock->ifchange_q );
+ async_wake_up( sock->ifchange_q, status );
+ free_async_queue( sock->ifchange_q );
+ sock->ifchange_q = NULL;
+ list_remove( &sock->ifchange_entry );
+ release_object( ifchange_object );
+}
+
+/* add interface change notification to a socket */
+int sock_add_ifchange( struct sock *sock, const async_data_t *async_data )
+{
+ struct object *ifchange = ifchange_object;
+ struct async *async;
+ struct fd *fd;
+
+ if (!sock->ifchange_q)
+ {
+ /* associate this socket with the interface change object */
+ ifchange = create_ifchange();
+ if (!ifchange) return FALSE;
+ ifchange_add_sock( ifchange, sock ); /* add this socket to the change notification list */
+ if (!(fd = ifchange_get_fd( ifchange ))) goto fail;
+ sock->ifchange_q = create_async_queue( fd );
+ release_object( fd );
+ if (!sock->ifchange_q) goto fail;
+ }
+ if (!(async = create_async( current, sock->ifchange_q, async_data ))) goto fail;
+ release_object( async );
+ return TRUE;
+
+fail:
+ free_async_queue( sock->ifchange_q );
+ sock->ifchange_q = NULL;
+ release_object( ifchange );
+ return FALSE;
+}
+
+static void ifchange_dump( struct object *obj, int verbose )
+{
+ assert( obj->ops == &ifchange_ops );
+ printf( "ifchange\n" );
+}
+
+static struct fd *ifchange_get_fd( struct object *obj )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ return (struct fd *)grab_object( ifchange->fd );
+}
+
+static void ifchange_destroy( struct object *obj )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ assert( obj->ops == &ifchange_ops );
+
+ /* reset the global ifchange object so that it will be recreated if it is needed again */
+ ifchange_object = NULL;
+ /* shut the socket down to force pending poll() calls in the client to return */
+ shutdown( get_unix_fd(ifchange->fd), SHUT_RDWR );
+ release_object( ifchange->fd );
+}
+
+static int ifchange_get_poll_events( struct fd *fd )
+{
+ return POLLIN;
+}
+
+/* wake up all the sockets waiting for a change notification event */
+static void ifchange_wake_up( struct object *obj, unsigned int status )
+{
+ struct ifchange *ifchange = (struct ifchange *) obj;
+ struct list *ptr, *next;
+
+ assert( obj->ops == &ifchange_ops );
+ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets )
+ {
+ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry );
+
+ sock_ifchange_wake_up( sock, status );
+ }
+}
+
+static void ifchange_poll_event( struct fd *fd, int event )
+{
+ struct object *ifchange = get_fd_user( fd );
+ int r, unix_fd, wakeup = FALSE;
+ char buffer[0x1000];
+
+ unix_fd = get_unix_fd( fd );
+ r = recv( unix_fd, buffer, sizeof(buffer), 0 );
+ if (r < 0)
+ {
+ fprintf(stderr,"ifchange_poll_event(): ifchange read failed!\n");
+ return;
+ }
+ else if (r != 0)
+ {
+#if defined(NETLINK_ROUTE)
+ struct nlmsghdr *nlh;
+
+ nlh = (struct nlmsghdr*) buffer;
+ if (NLMSG_OK(nlh, r) && (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR))
+ wakeup = TRUE;
+#endif
+ }
+ if (wakeup)
+ ifchange_wake_up( ifchange, STATUS_SUCCESS );
+}
+
+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue )
+{
+ /* do nothing, this object is about to disappear */
+}
+
/* create a socket */
DECL_HANDLER(create_socket)
{
--
1.7.9.5

View File

@@ -0,0 +1,98 @@
From 39b9fb0ed11366e00d5b565303580bb7e9c3259b Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 4 Oct 2013 08:24:15 -0600
Subject: ws2_32: Add an interactive test for interface change notifications.
---
dlls/ws2_32/tests/sock.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index ac6ee10..66509b3 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -6225,6 +6225,73 @@ static void test_sioRoutingInterfaceQuery(void)
closesocket(sock);
}
+static void test_sioAddressListChange(void)
+{
+ struct sockaddr_in bindAddress;
+ struct in_addr net_address;
+ WSAOVERLAPPED overlapped;
+ struct hostent *h;
+ DWORD num_bytes;
+ SOCKET sock;
+ int acount;
+ int ret;
+
+ if (!winetest_interactive)
+ {
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, interactive tests must be enabled\n");
+ return;
+ }
+
+ /* Use gethostbyname to find the list of local network interfaces */
+ h = gethostbyname("");
+ if (!h)
+ {
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, gethostbyname failed with %u\n",
+ WSAGetLastError());
+ return;
+ }
+ for (acount = 0; h->h_addr_list[acount]; acount++);
+ if (acount == 0)
+ {
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, test requires a network cards.\n");
+ return;
+ }
+ net_address.s_addr = *(ULONG *) h->h_addr_list[0];
+
+ /* Bind an overlapped socket to the first found network interface */
+ sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+ ok(sock != INVALID_SOCKET, "Expected socket to return a valid socket\n");
+ if (sock == INVALID_SOCKET)
+ {
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, socket creation failed with %u\n",
+ WSAGetLastError());
+ return;
+ }
+ memset(&bindAddress, 0, sizeof(bindAddress));
+ bindAddress.sin_family = AF_INET;
+ bindAddress.sin_addr.s_addr = net_address.s_addr;
+ ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
+ if (ret != 0)
+ {
+ skip("Cannot test SIO_ADDRESS_LIST_CHANGE, failed to bind, error %u\n", WSAGetLastError());
+ goto end;
+ }
+
+ /* Wait for address changes, request that the user connect/disconnect an interface */
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ ret = WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, &overlapped, NULL);
+ ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n");
+ ok(WSAGetLastError() == WSA_IO_PENDING, "Expected pending last error %d\n", WSAGetLastError());
+ trace("Testing socket-based ipv4 address list change notification. Please connect/disconnect or"
+ " change the ipv4 address of any of the local network interfaces (10 second timeout).\n");
+ ret = WaitForSingleObject(overlapped.hEvent, 10000);
+ ok(ret == WAIT_OBJECT_0, "failed to get overlapped event %u\n", ret);
+
+end:
+ closesocket(sock);
+}
+
static void test_synchronous_WSAIoctl(void)
{
HANDLE previous_port, io_port;
@@ -7101,6 +7168,7 @@ START_TEST( sock )
test_ConnectEx();
test_sioRoutingInterfaceQuery();
+ test_sioAddressListChange();
test_WSAAsyncGetServByPort();
test_WSAAsyncGetServByName();
--
1.7.9.5

View File

@@ -0,0 +1,205 @@
From 8ffcfda480ef0475910eee359c8e447571b078cf Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 9 Aug 2013 20:56:15 -0600
Subject: server: Create directories with the specified security attributes.
---
dlls/kernel32/tests/directory.c | 135 +++++++++++++++++++++++++++++++++++++++
server/fd.c | 2 +-
server/file.c | 7 +-
3 files changed, 142 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/directory.c b/dlls/kernel32/tests/directory.c
index 9baae47..df434b6 100644
--- a/dlls/kernel32/tests/directory.c
+++ b/dlls/kernel32/tests/directory.c
@@ -24,6 +24,15 @@
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "aclapi.h"
+
+static DWORD (WINAPI *pGetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION,
+ PSID*, PSID*, PACL*, PACL*,
+ PSECURITY_DESCRIPTOR*);
+static BOOL (WINAPI *pGetAclInformation)(PACL,LPVOID,DWORD,ACL_INFORMATION_CLASS);
+static BOOL (WINAPI *pCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*);
+static BOOL (WINAPI *pAddAccessAllowedAceEx)(PACL, DWORD, DWORD, DWORD, PSID);
+static BOOL (WINAPI *pGetAce)(PACL,DWORD,LPVOID*);
/* If you change something in these tests, please do the same
* for GetSystemDirectory tests.
@@ -486,8 +495,132 @@ static void test_SetCurrentDirectoryA(void)
ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %d\n", GetLastError() );
}
+static void test_security_attributes(void)
+{
+ char admin_ptr[sizeof(SID)+sizeof(ULONG)*SID_MAX_SUB_AUTHORITIES], *user;
+ DWORD sid_size = sizeof(admin_ptr), user_size;
+ PSID admin_sid = (PSID) admin_ptr, user_sid;
+ char sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR pSD = &sd;
+ ACL_SIZE_INFORMATION acl_size;
+ ACCESS_ALLOWED_ACE *ace;
+ SECURITY_ATTRIBUTES sa;
+ char tmpdir[MAX_PATH];
+ struct _SID *owner;
+ BOOL bret = TRUE;
+ HANDLE token;
+ DWORD error;
+ PACL pDacl;
+
+ if (!pGetNamedSecurityInfoA || !pCreateWellKnownSid)
+ {
+ win_skip("Required functions are not available\n");
+ return;
+ }
+
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token))
+ {
+ if (GetLastError() != ERROR_NO_TOKEN) bret = FALSE;
+ else if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token)) bret = FALSE;
+ }
+ if (!bret)
+ {
+ win_skip("Failed to get current user token\n");
+ return;
+ }
+ bret = GetTokenInformation(token, TokenUser, NULL, 0, &user_size);
+ ok(!bret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
+ "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError());
+ user = HeapAlloc(GetProcessHeap(), 0, user_size);
+ bret = GetTokenInformation(token, TokenUser, user, user_size, &user_size);
+ ok(bret, "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError());
+ CloseHandle( token );
+ user_sid = ((TOKEN_USER *)user)->User.Sid;
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = pSD;
+ sa.bInheritHandle = TRUE;
+ InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
+ pCreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size);
+ pDacl = HeapAlloc(GetProcessHeap(), 0, 100);
+ bret = InitializeAcl(pDacl, 100, ACL_REVISION);
+ ok(bret, "Failed to initialize ACL.\n");
+ bret = pAddAccessAllowedAceEx(pDacl, ACL_REVISION, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE,
+ GENERIC_ALL, user_sid);
+ ok(bret, "Failed to add Current User to ACL.\n");
+ bret = pAddAccessAllowedAceEx(pDacl, ACL_REVISION, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE,
+ GENERIC_ALL, admin_sid);
+ ok(bret, "Failed to add Administrator Group to ACL.\n");
+ bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE);
+ ok(bret, "Failed to add ACL to security desciptor.\n");
+
+ GetTempPathA(MAX_PATH, tmpdir);
+ lstrcatA(tmpdir, "Please Remove Me");
+ bret = CreateDirectoryA(tmpdir, &sa);
+ ok(bret == TRUE, "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError());
+ HeapFree(GetProcessHeap(), 0, pDacl);
+
+ SetLastError(0xdeadbeef);
+ error = pGetNamedSecurityInfoA(tmpdir, SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, (PSID*)&owner,
+ NULL, &pDacl, NULL, &pSD);
+ if (error != ERROR_SUCCESS && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+ {
+ win_skip("GetNamedSecurityInfoA is not implemented\n");
+ goto done;
+ }
+ ok(!error, "GetNamedSecurityInfo failed with error %d\n", error);
+
+ bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ ok(bret, "GetAclInformation failed\n");
+ ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n",
+ acl_size.AceCount);
+ if (acl_size.AceCount > 0)
+ {
+ bret = pGetAce(pDacl, 0, (VOID **)&ace);
+ ok(bret, "Failed to get Current User ACE.\n");
+ bret = EqualSid(&ace->SidStart, user_sid);
+ todo_wine ok(bret, "Current User ACE != Current User SID.\n");
+ todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
+ "Current User ACE has unexpected flags (0x%x != 0x03)\n",
+ ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ if (acl_size.AceCount > 1)
+ {
+ bret = pGetAce(pDacl, 1, (VOID **)&ace);
+ ok(bret, "Failed to get Administators Group ACE.\n");
+ bret = EqualSid(&ace->SidStart, admin_sid);
+ todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n");
+ todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
+ "Administators Group ACE has unexpected flags (0x%x != 0x03)\n",
+ ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+
+done:
+ HeapFree(GetProcessHeap(), 0, user);
+ bret = RemoveDirectoryA(tmpdir);
+ ok(bret == TRUE, "RemoveDirectoryA should always succeed\n");
+}
+
+void init(void)
+{
+ HMODULE hmod = GetModuleHandle("advapi32.dll");
+
+ pGetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "GetNamedSecurityInfoA");
+ pAddAccessAllowedAceEx = (void *)GetProcAddress(hmod, "AddAccessAllowedAceEx");
+ pCreateWellKnownSid = (void *)GetProcAddress(hmod, "CreateWellKnownSid");
+ pGetAclInformation = (void *)GetProcAddress(hmod, "GetAclInformation");
+ pGetAce = (void *)GetProcAddress(hmod, "GetAce");
+}
+
START_TEST(directory)
{
+ init();
+
test_GetWindowsDirectoryA();
test_GetWindowsDirectoryW();
@@ -501,4 +634,6 @@ START_TEST(directory)
test_RemoveDirectoryW();
test_SetCurrentDirectoryA();
+
+ test_security_attributes();
}
diff --git a/server/fd.c b/server/fd.c
index f3e42bd..248f15a 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1765,7 +1765,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
/* create the directory if needed */
if ((options & FILE_DIRECTORY_FILE) && (flags & O_CREAT))
{
- if (mkdir( name, 0777 ) == -1)
+ if (mkdir( name, *mode ) == -1)
{
if (errno != EEXIST || (flags & O_EXCL))
{
diff --git a/server/file.c b/server/file.c
index 2ecf97c..9c6cb80 100644
--- a/server/file.c
+++ b/server/file.c
@@ -219,7 +219,12 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
mode = sd_to_mode( sd, owner );
}
else
- mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
+ {
+ if (options & FILE_NON_DIRECTORY_FILE)
+ mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
+ else
+ mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0555 : 0777;
+ }
if (len >= 4 &&
(!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" )))
--
1.7.9.5

View File

@@ -0,0 +1,491 @@
From 1c8bf1825218528541076451f35b5c1f3c04add3 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 3 Oct 2013 13:27:30 -0600
Subject: server: Store and return security attributes with extended file
attributes.
---
configure.ac | 1 +
dlls/advapi32/tests/security.c | 9 +-
dlls/kernel32/tests/directory.c | 15 ++--
server/change.c | 11 ++-
server/fd.c | 68 ++++++++++++++-
server/file.c | 176 ++++++++++++++++++++++++++++++++++++++-
server/file.h | 5 +-
7 files changed, 263 insertions(+), 22 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8ad29db..b7a3098 100644
--- a/configure.ac
+++ b/configure.ac
@@ -410,6 +410,7 @@ AC_CHECK_HEADERS(\
arpa/nameser.h \
asm/types.h \
asm/user.h \
+ attr/xattr.h \
curses.h \
direct.h \
dirent.h \
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index c622bb2..4c9e8d4 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -3166,7 +3166,7 @@ static void test_GetNamedSecurityInfoA(void)
bret = pGetAce(pDacl, 0, (VOID **)&ace);
ok(bret, "Failed to get Current User ACE.\n");
bret = EqualSid(&ace->SidStart, user_sid);
- todo_wine ok(bret, "Current User ACE != Current User SID.\n");
+ ok(bret, "Current User ACE != Current User SID.\n");
ok(((ACE_HEADER *)ace)->AceFlags == 0,
"Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
@@ -3177,8 +3177,7 @@ static void test_GetNamedSecurityInfoA(void)
bret = pGetAce(pDacl, 1, (VOID **)&ace);
ok(bret, "Failed to get Administators Group ACE.\n");
bret = EqualSid(&ace->SidStart, admin_sid);
- todo_wine ok(bret || broken(!bret) /* win2k */,
- "Administators Group ACE != Administators Group SID.\n");
+ ok(bret || broken(!bret) /* win2k */, "Administators Group ACE != Administators Group SID.\n");
ok(((ACE_HEADER *)ace)->AceFlags == 0,
"Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff || broken(ace->Mask == GENERIC_ALL) /* win2k */,
@@ -3832,7 +3831,7 @@ static void test_GetSecurityInfo(void)
bret = pGetAce(pDacl, 0, (VOID **)&ace);
ok(bret, "Failed to get Current User ACE.\n");
bret = EqualSid(&ace->SidStart, user_sid);
- todo_wine ok(bret, "Current User ACE != Current User SID.\n");
+ ok(bret, "Current User ACE != Current User SID.\n");
ok(((ACE_HEADER *)ace)->AceFlags == 0,
"Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
@@ -3843,7 +3842,7 @@ static void test_GetSecurityInfo(void)
bret = pGetAce(pDacl, 1, (VOID **)&ace);
ok(bret, "Failed to get Administators Group ACE.\n");
bret = EqualSid(&ace->SidStart, admin_sid);
- todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n");
+ ok(bret, "Administators Group ACE != Administators Group SID.\n");
ok(((ACE_HEADER *)ace)->AceFlags == 0,
"Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
diff --git a/dlls/kernel32/tests/directory.c b/dlls/kernel32/tests/directory.c
index df434b6..a8dfa81 100644
--- a/dlls/kernel32/tests/directory.c
+++ b/dlls/kernel32/tests/directory.c
@@ -580,10 +580,9 @@ static void test_security_attributes(void)
bret = pGetAce(pDacl, 0, (VOID **)&ace);
ok(bret, "Failed to get Current User ACE.\n");
bret = EqualSid(&ace->SidStart, user_sid);
- todo_wine ok(bret, "Current User ACE != Current User SID.\n");
- todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
- "Current User ACE has unexpected flags (0x%x != 0x03)\n",
- ((ACE_HEADER *)ace)->AceFlags);
+ ok(bret, "Current User ACE != Current User SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
+ "Current User ACE has unexpected flags (0x%x != 0x03)\n", ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
ace->Mask);
}
@@ -592,10 +591,10 @@ static void test_security_attributes(void)
bret = pGetAce(pDacl, 1, (VOID **)&ace);
ok(bret, "Failed to get Administators Group ACE.\n");
bret = EqualSid(&ace->SidStart, admin_sid);
- todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n");
- todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
- "Administators Group ACE has unexpected flags (0x%x != 0x03)\n",
- ((ACE_HEADER *)ace)->AceFlags);
+ ok(bret, "Administators Group ACE != Administators Group SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
+ "Administators Group ACE has unexpected flags (0x%x != 0x03)\n",
+ ((ACE_HEADER *)ace)->AceFlags);
ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
ace->Mask);
}
diff --git a/server/change.c b/server/change.c
index f6d56b0..022c780 100644
--- a/server/change.c
+++ b/server/change.c
@@ -286,6 +286,7 @@ static int get_dir_unix_fd( struct dir *dir )
static struct security_descriptor *dir_get_sd( struct object *obj )
{
struct dir *dir = (struct dir *)obj;
+ const SID *user, *group;
int unix_fd;
struct stat st;
struct security_descriptor *sd;
@@ -302,9 +303,11 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
(st.st_uid == dir->uid))
return obj->sd;
- sd = mode_to_sd( st.st_mode,
- security_unix_uid_to_sid( st.st_uid ),
- token_get_primary_group( current->process->token ));
+ user = security_unix_uid_to_sid( st.st_uid );
+ group = token_get_primary_group( current->process->token );
+ sd = get_file_acls( unix_fd, user, group );
+ if (!sd)
+ sd = mode_to_sd( st.st_mode, user, group );
if (!sd) return obj->sd;
dir->mode = st.st_mode;
@@ -353,6 +356,8 @@ static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
mode |= sd_to_mode( sd, owner );
+ set_file_acls( unix_fd, sd );
+
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
{
file_set_error();
diff --git a/server/fd.c b/server/fd.c
index fa8874c..98e3eca 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -91,6 +91,9 @@
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -99,6 +102,7 @@
#include "handle.h"
#include "process.h"
#include "request.h"
+#include "security.h"
#include "winternl.h"
#include "winioctl.h"
@@ -1726,9 +1730,69 @@ static char *dup_fd_name( struct fd *root, const char *name )
return ret;
}
+void set_file_acls( int fd, const struct security_descriptor *sd )
+{
+#ifdef HAVE_ATTR_XATTR_H
+ char buffer[XATTR_SIZE_MAX], *p = buffer;
+ const ACE_HEADER *ace;
+ int present, i, j, n;
+ const ACL *dacl;
+
+ if (!sd) return;
+ dacl = sd_get_dacl( sd, &present );
+ if (!present || !dacl) return;
+ ace = (const ACE_HEADER *)(dacl + 1);
+
+ for (i = 0; i < dacl->AceCount; i++, ace = ace_next( ace ))
+ {
+ BYTE type = ace->AceType, flags;
+ const ACCESS_ALLOWED_ACE *aaa;
+ const ACCESS_DENIED_ACE *ada;
+ char sidtxt[100], *s;
+ const SID *sid;
+ DWORD mask;
+
+ if (type & INHERIT_ONLY_ACE) continue;
+
+ switch (type)
+ {
+ case ACCESS_DENIED_ACE_TYPE:
+ ada = (const ACCESS_DENIED_ACE *)ace;
+ flags = ada->Header.AceFlags;
+ mask = ada->Mask;
+ sid = (const SID *)&ada->SidStart;
+ break;
+ case ACCESS_ALLOWED_ACE_TYPE:
+ aaa = (const ACCESS_ALLOWED_ACE *)ace;
+ flags = aaa->Header.AceFlags;
+ mask = aaa->Mask;
+ sid = (const SID *)&aaa->SidStart;
+ break;
+ default:
+ continue;
+ }
+ n = sprintf( sidtxt, "S-%u-%d", sid->Revision,
+ MAKELONG(
+ MAKEWORD( sid->IdentifierAuthority.Value[5],
+ sid->IdentifierAuthority.Value[4] ),
+ MAKEWORD( sid->IdentifierAuthority.Value[3],
+ sid->IdentifierAuthority.Value[2] )
+ ) );
+ s = sidtxt + n;
+ for( j=0; j<sid->SubAuthorityCount; j++ )
+ s += sprintf( s, "-%u", sid->SubAuthority[j] );
+
+ p += snprintf( p, XATTR_SIZE_MAX-(p-buffer), "%s%x,%x,%x,%s",
+ (p != buffer ? ";" : ""), type, flags, mask, sidtxt );
+ }
+
+ fsetxattr( fd, "user.wine.acl", buffer, p-buffer, 0 );
+#endif
+}
+
/* open() wrapper that returns a struct fd with no fd user set */
struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access,
- unsigned int sharing, unsigned int options )
+ unsigned int sharing, unsigned int options, const struct security_descriptor *sd )
{
struct stat st;
struct closed_fd *closed_fd;
@@ -1804,6 +1868,8 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
}
}
+ set_file_acls( fd->unix_fd, sd );
+
closed_fd->unix_fd = fd->unix_fd;
closed_fd->unlink[0] = 0;
fstat( fd->unix_fd, &st );
diff --git a/server/file.c b/server/file.c
index 9c6cb80..f4d97fd 100644
--- a/server/file.c
+++ b/server/file.c
@@ -32,6 +32,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
+#include <limits.h>
#include <unistd.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
@@ -39,6 +40,9 @@
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -240,7 +244,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
access = generic_file_map_access( access );
/* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */
- fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options );
+ fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options, sd );
if (!fd) goto done;
if (S_ISDIR(mode))
@@ -427,9 +431,169 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID
return sd;
}
+struct security_descriptor *get_file_acls( int fd, const SID *user, const SID *group )
+{
+#ifdef HAVE_ATTR_XATTR_H
+ int ace_count = 0, dacl_size = sizeof(ACL), i, n;
+ char buffer[XATTR_SIZE_MAX], *p = buffer, *pn;
+ struct security_descriptor *sd;
+ ACE_HEADER *current_ace;
+ ACCESS_ALLOWED_ACE *aaa;
+ ACCESS_DENIED_ACE *ada;
+ int type, flags, mask;
+ ACL *dacl;
+ char *ptr;
+
+ n = fgetxattr( fd, "user.wine.acl", buffer, sizeof(buffer) );
+ if (n == -1) return NULL;
+ buffer[n] = 0;
+
+ do
+ {
+ int sub_authority_count = 0;
+
+ pn = strchr(p, ';');
+ if (pn) pn++;
+ sscanf(p, "%x", &type);
+ do
+ {
+ p = strchr(p, '-');
+ if (p) p++;
+ sub_authority_count++;
+ }
+ while(p && (!pn || p < pn));
+ sub_authority_count -= 3; /* Revision and IdentifierAuthority don't count */
+
+ switch (type)
+ {
+ case ACCESS_DENIED_ACE_TYPE:
+ dacl_size += FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) +
+ FIELD_OFFSET(SID, SubAuthority[sub_authority_count]);
+ break;
+ case ACCESS_ALLOWED_ACE_TYPE:
+ dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
+ FIELD_OFFSET(SID, SubAuthority[sub_authority_count]);
+ break;
+ default:
+ continue;
+ }
+ ace_count++;
+ p = pn;
+ }
+ while(p);
+
+ sd = mem_alloc( sizeof(struct security_descriptor) +
+ FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]) +
+ FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]) +
+ dacl_size );
+
+ sd->control = SE_DACL_PRESENT;
+ sd->owner_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]);
+ sd->group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]);
+ sd->sacl_len = 0;
+ sd->dacl_len = dacl_size;
+
+ ptr = (char *)(sd + 1);
+ memcpy( ptr, user, sd->owner_len );
+ ptr += sd->owner_len;
+ memcpy( ptr, group, sd->group_len );
+ ptr += sd->group_len;
+
+ dacl = (ACL *)ptr;
+ dacl->AclRevision = ACL_REVISION;
+ dacl->Sbz1 = 0;
+ dacl->AclSize = dacl_size;
+ dacl->AceCount = ace_count;
+ dacl->Sbz2 = 0;
+ aaa = (ACCESS_ALLOWED_ACE *)(dacl + 1);
+ current_ace = &aaa->Header;
+
+ p = buffer;
+ for(i=0; i<ace_count; i++)
+ {
+ char b[sizeof(SID) + sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES];
+ int sub_authority_count = 0;
+ SID *sid = (SID *)&b[0];
+ char sidtxt[100];
+ int rev, ia, sa;
+
+ if (i != 0)
+ {
+ aaa = (ACCESS_ALLOWED_ACE *)ace_next( current_ace );
+ current_ace = &aaa->Header;
+ }
+ pn = strchr(p, ';');
+ if (pn) pn++;
+ sscanf(p, "%x,%x,%x,%[^;]", &type, &flags, &mask, sidtxt);
+ sscanf(sidtxt, "S-%u-%d", &rev, &ia);
+ sid->Revision = rev;
+ sid->IdentifierAuthority.Value[0] = 0;
+ sid->IdentifierAuthority.Value[1] = 0;
+ sid->IdentifierAuthority.Value[2] = HIBYTE(HIWORD(ia));
+ sid->IdentifierAuthority.Value[3] = LOBYTE(HIWORD(ia));
+ sid->IdentifierAuthority.Value[4] = HIBYTE(LOWORD(ia));
+ sid->IdentifierAuthority.Value[5] = LOBYTE(LOWORD(ia));
+ p = strchr(sidtxt, '-')+1;
+ p = strchr(p, '-')+1; /* Revision doesn't count */
+ p = strchr(p, '-')+1; /* IdentifierAuthority doesn't count */
+ do
+ {
+ sscanf(p, "%u", &sa);
+ sid->SubAuthority[sub_authority_count] = sa;
+ p = strchr(p, '-');
+ if (p) p++;
+ sub_authority_count++;
+ }
+ while(p);
+ sid->SubAuthorityCount = sub_authority_count;
+
+ /* Convert generic rights into standard access rights */
+ if (mask & GENERIC_ALL)
+ mask |= WRITE_DAC | WRITE_OWNER | DELETE | FILE_DELETE_CHILD;
+ if (mask & (GENERIC_ALL|GENERIC_READ))
+ mask |= FILE_GENERIC_READ;
+ if (mask & (GENERIC_ALL|GENERIC_WRITE))
+ mask |= FILE_GENERIC_WRITE;
+ if (mask & (GENERIC_ALL|GENERIC_EXECUTE))
+ mask |= FILE_GENERIC_EXECUTE;
+ mask &= 0x0FFFFFFF;
+
+ /* Handle the specific ACE */
+ switch (type)
+ {
+ case ACCESS_DENIED_ACE_TYPE:
+ ada = (ACCESS_DENIED_ACE *)aaa;
+ ada->Header.AceType = type;
+ ada->Header.AceFlags = flags;
+ ada->Header.AceSize = FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) +
+ FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]);
+ ada->Mask = mask;
+ memcpy( &ada->SidStart, sid, FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]) );
+ break;
+ case ACCESS_ALLOWED_ACE_TYPE:
+ aaa->Header.AceType = type;
+ aaa->Header.AceFlags = flags;
+ aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
+ FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]);
+ aaa->Mask = mask;
+ memcpy( &aaa->SidStart, sid, FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]) );
+ break;
+ default:
+ continue;
+ }
+ p = pn;
+ }
+
+ return sd;
+#else
+ return NULL;
+#endif
+}
+
static struct security_descriptor *file_get_sd( struct object *obj )
{
struct file *file = (struct file *)obj;
+ const SID *user, *group;
struct stat st;
int unix_fd;
struct security_descriptor *sd;
@@ -446,9 +610,11 @@ static struct security_descriptor *file_get_sd( struct object *obj )
(st.st_uid == file->uid))
return obj->sd;
- sd = mode_to_sd( st.st_mode,
- security_unix_uid_to_sid( st.st_uid ),
- token_get_primary_group( current->process->token ));
+ user = security_unix_uid_to_sid( st.st_uid );
+ group = token_get_primary_group( current->process->token );
+ sd = get_file_acls( unix_fd, user, group );
+ if (!sd)
+ sd = mode_to_sd( st.st_mode, user, group);
if (!sd) return obj->sd;
file->mode = st.st_mode;
@@ -578,6 +744,8 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
mode |= sd_to_mode( sd, owner );
+ set_file_acls( unix_fd, sd );
+
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
{
file_set_error();
diff --git a/server/file.h b/server/file.h
index aae8b20..2d744eb 100644
--- a/server/file.h
+++ b/server/file.h
@@ -56,7 +56,8 @@ extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct obje
unsigned int options );
extern void set_no_fd_status( struct fd *fd, unsigned int status );
extern struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
- unsigned int access, unsigned int sharing, unsigned int options );
+ unsigned int access, unsigned int sharing, unsigned int options,
+ const struct security_descriptor *sd );
extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops,
int unix_fd, struct object *user, unsigned int options );
extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing,
@@ -122,6 +123,8 @@ extern struct file *create_file_for_fd_obj( struct fd *fd, unsigned int access,
extern void file_set_error(void);
extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group );
extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
+extern void set_file_acls( int fd, const struct security_descriptor *sd );
+extern struct security_descriptor *get_file_acls( int fd, const SID *user, const SID *group );
/* file mapping functions */
--
1.7.9.5

View File

@@ -0,0 +1,180 @@
From c4219ad0d05c2e61b4d3408b2b8c57d762a58c4b Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Fri, 9 Aug 2013 20:57:23 -0600
Subject: ntdll: Inherit security attributes from parent directories.
---
dlls/kernel32/tests/directory.c | 40 +++++++++++++++++-
dlls/ntdll/file.c | 85 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 123 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/directory.c b/dlls/kernel32/tests/directory.c
index a8dfa81..a3a9580 100644
--- a/dlls/kernel32/tests/directory.c
+++ b/dlls/kernel32/tests/directory.c
@@ -505,10 +505,11 @@ static void test_security_attributes(void)
ACL_SIZE_INFORMATION acl_size;
ACCESS_ALLOWED_ACE *ace;
SECURITY_ATTRIBUTES sa;
+ char tmpfile[MAX_PATH];
char tmpdir[MAX_PATH];
+ HANDLE token, hTemp;
struct _SID *owner;
BOOL bret = TRUE;
- HANDLE token;
DWORD error;
PACL pDacl;
@@ -599,6 +600,43 @@ static void test_security_attributes(void)
ace->Mask);
}
+ /* Test inheritance of ACLs */
+ strcpy(tmpfile, tmpdir);
+ lstrcatA(tmpfile, "/tmpfile");
+ hTemp = CreateFileA(tmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW,
+ FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, (PSID*)&owner,
+ NULL, &pDacl, NULL, &pSD);
+ ok(error == ERROR_SUCCESS, "Failed to get permissions on file.\n");
+ bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ ok(bret, "GetAclInformation failed\n");
+ ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n",
+ acl_size.AceCount);
+ if (acl_size.AceCount > 0)
+ {
+ bret = pGetAce(pDacl, 0, (VOID **)&ace);
+ ok(bret, "Inherited Failed to get Current User ACE.\n");
+ bret = EqualSid(&ace->SidStart, user_sid);
+ ok(bret, "Inherited Current User ACE != Current User SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
+ "Inherited Current User ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ if (acl_size.AceCount > 1)
+ {
+ bret = pGetAce(pDacl, 1, (VOID **)&ace);
+ ok(bret, "Inherited Failed to get Administators Group ACE.\n");
+ bret = EqualSid(&ace->SidStart, admin_sid);
+ ok(bret, "Inherited Administators Group ACE != Administators Group SID.\n");
+ ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE,
+ "Inherited Administators Group ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags);
+ ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
+ ace->Mask);
+ }
+ CloseHandle(hTemp);
+
done:
HeapFree(GetProcessHeap(), 0, user);
bret = RemoveDirectoryA(tmpdir);
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5147ef5..79a700c 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -94,6 +94,81 @@ mode_t FILE_umask = 0;
static const WCHAR ntfsW[] = {'N','T','F','S'};
+static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIBUTES attr,
+ PIO_STATUS_BLOCK io, PLARGE_INTEGER alloc_size,
+ ULONG attributes, ULONG sharing, ULONG disposition,
+ ULONG options, PVOID ea_buffer, ULONG ea_length );
+
+struct security_descriptor *FILE_get_parent_sd(UNICODE_STRING *filenameW)
+{
+ SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION
+ |DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION;
+ PSECURITY_DESCRIPTOR parentsd = NULL;
+ ACL_SIZE_INFORMATION acl_size;
+ BOOLEAN present, defaulted;
+ WCHAR *p, parent[MAX_PATH];
+ OBJECT_ATTRIBUTES pattr;
+ UNICODE_STRING parentW;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE hparent;
+ ULONG n1, n2;
+ PACL pDacl;
+ int i;
+
+ parentW.Buffer = parent;
+ parentW.Length = filenameW->Length;
+ memcpy(parentW.Buffer, filenameW->Buffer, filenameW->Length);
+ if ((p = strrchrW(parent, '\\')) != NULL)
+ {
+ p[0] = 0;
+ parentW.Length = (p-parent)*sizeof(WCHAR);
+ }
+ memset(&pattr, 0x0, sizeof(pattr));
+ pattr.Length = sizeof(pattr);
+ pattr.Attributes = OBJ_CASE_INSENSITIVE;
+ pattr.ObjectName = &parentW;
+ status = FILE_CreateFile( &hparent, READ_CONTROL|ACCESS_SYSTEM_SECURITY, &pattr, &io, NULL,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,
+ FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0 );
+ if (status == STATUS_SUCCESS)
+ status = NtQuerySecurityObject( hparent, info, NULL, 0, &n1 );
+ if (status == STATUS_BUFFER_TOO_SMALL && (parentsd = RtlAllocateHeap( GetProcessHeap(), 0, n1 )) != NULL)
+ status = NtQuerySecurityObject( hparent, info, parentsd, n1, &n2 );
+ if (status == STATUS_SUCCESS)
+ status = NtQuerySecurityObject( hparent, info, parentsd, n1, &n2 );
+ if (hparent != INVALID_HANDLE_VALUE)
+ NtClose( hparent );
+ if (status != STATUS_SUCCESS) return NULL;
+ status = RtlGetDaclSecurityDescriptor(parentsd, &present, &pDacl, &defaulted);
+ if (status != STATUS_SUCCESS || !present) return NULL;
+ status = RtlQueryInformationAcl(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
+ if (status != STATUS_SUCCESS) return NULL;
+
+ for (i=acl_size.AceCount-1; i>=0; i--)
+ {
+ DWORD inheritance_mask = INHERIT_ONLY_ACE|OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE;
+ ACE_HEADER *ace;
+
+ status = RtlGetAce(pDacl, i, (VOID **)&ace);
+ if (status != STATUS_SUCCESS || !(ace->AceFlags & inheritance_mask))
+ {
+ RtlDeleteAce(pDacl, i);
+ acl_size.AceCount--;
+ }
+ else
+ ace->AceFlags = (ace->AceFlags & ~inheritance_mask) | INHERITED_ACE;
+ }
+
+ if (!acl_size.AceCount)
+ {
+ return NULL;
+ }
+ return parentsd;
+}
+
+
/**************************************************************************
* FILE_CreateFile (internal)
* Open a file.
@@ -152,10 +227,18 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT
{
struct security_descriptor *sd;
struct object_attributes objattr;
+ PSECURITY_DESCRIPTOR parentsd = NULL, psd;
objattr.rootdir = wine_server_obj_handle( attr->RootDirectory );
objattr.name_len = 0;
- io->u.Status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
+ psd = attr->SecurityDescriptor;
+ if (!psd && (disposition == FILE_CREATE||disposition == FILE_OVERWRITE_IF))
+ parentsd = FILE_get_parent_sd( attr->ObjectName );
+ if (parentsd)
+ psd = parentsd;
+ io->u.Status = NTDLL_create_struct_sd( psd, &sd, &objattr.sd_len );
+ if (parentsd)
+ RtlFreeHeap( GetProcessHeap(), 0, parentsd );
if (io->u.Status != STATUS_SUCCESS)
{
RtlFreeAnsiString( &unix_name );
--
1.7.9.5

View File

@@ -0,0 +1,25 @@
From d027a6891aa48f2614b606892bc54e25e147eee2 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sun, 11 Aug 2013 17:45:19 -0600
Subject: kernel32: Allow string comparison with linguistic casing.
---
dlls/kernel32/locale.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 9ddf078..d635364 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -2934,7 +2934,7 @@ INT WINAPI CompareStringEx(LPCWSTR locale, DWORD flags, LPCWSTR str1, INT len1,
return 0;
}
- if( flags & ~(NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS|
+ if( flags & ~(NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS|NORM_LINGUISTIC_CASING|
SORT_STRINGSORT|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH|LOCALE_USE_CP_ACP|0x10000000) )
{
SetLastError(ERROR_INVALID_FLAGS);
--
1.7.9.5

View File

@@ -0,0 +1,65 @@
From 95de7ce5572ff82805bbee85a2af72d0b221371c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 10 Nov 2013 20:44:10 +0100
Subject: quartz: Implement better stubs for AMCertifiedOutputProtection
---
dlls/quartz/vmr9.c | 8 ++++----
include/vfwmsgs.h | 1 +
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c
index 2dc12a6..0acdd26 100644
--- a/dlls/quartz/vmr9.c
+++ b/dlls/quartz/vmr9.c
@@ -1120,7 +1120,7 @@ static HRESULT WINAPI AMCertifiedOutputProtection_KeyExchange(IAMCertifiedOutput
struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
FIXME("(%p/%p)->(%p, %p, %p) stub\n", iface, This, pRandom, VarLenCertGH, pdwLengthCertGH);
- return E_NOTIMPL;
+ return VFW_E_NO_COPP_HW;
}
static HRESULT WINAPI AMCertifiedOutputProtection_SessionSequenceStart(IAMCertifiedOutputProtection *iface,
@@ -1129,7 +1129,7 @@ static HRESULT WINAPI AMCertifiedOutputProtection_SessionSequenceStart(IAMCertif
struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, pSig);
- return E_NOTIMPL;
+ return VFW_E_NO_COPP_HW;
}
static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionCommand(IAMCertifiedOutputProtection *iface,
@@ -1138,7 +1138,7 @@ static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionCommand(IAMCertified
struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, cmd);
- return E_NOTIMPL;
+ return VFW_E_NO_COPP_HW;
}
static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionStatus(IAMCertifiedOutputProtection *iface,
@@ -1148,7 +1148,7 @@ static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionStatus(IAMCertifiedO
struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
FIXME("(%p/%p)->(%p, %p) stub\n", iface, This, pStatusInput, pStatusOutput);
- return E_NOTIMPL;
+ return VFW_E_NO_COPP_HW;
}
static const IAMCertifiedOutputProtectionVtbl IAMCertifiedOutputProtection_Vtbl =
diff --git a/include/vfwmsgs.h b/include/vfwmsgs.h
index 16b25c3..660ee40 100644
--- a/include/vfwmsgs.h
+++ b/include/vfwmsgs.h
@@ -156,6 +156,7 @@
#define VFW_E_VMR_NO_AP_SUPPLIED ((HRESULT)0x80040297)
#define VFW_E_VMR_NO_DEINTERLACE_HW ((HRESULT)0x80040298)
#define VFW_E_DVD_VMR9_INCOMPATIBLEDEC ((HRESULT)0x8004029A)
+#define VFW_E_NO_COPP_HW ((HRESULT)0x8004029B)
#define VFW_E_BAD_KEY ((HRESULT)0x800403F2)
#ifndef E_PROP_ID_UNSUPPORTED
--
1.7.9.5

View File

@@ -0,0 +1,122 @@
From beed64a33606fd3de77f41708f8a2b590521ea51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 10 Nov 2013 21:40:10 +0100
Subject: quartz: Partial implementation of VMR7MonitorConfig
---
dlls/quartz/vmr9.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 64 insertions(+), 6 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c
index 0acdd26..6b2970b 100644
--- a/dlls/quartz/vmr9.c
+++ b/dlls/quartz/vmr9.c
@@ -1309,7 +1309,7 @@ static HRESULT WINAPI VMR7MonitorConfig_SetMonitor(IVMRMonitorConfig *iface, con
struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
- return E_NOTIMPL;
+ return S_OK;
}
static HRESULT WINAPI VMR7MonitorConfig_GetMonitor(IVMRMonitorConfig *iface, VMRGUID *pGUID)
@@ -1317,7 +1317,11 @@ static HRESULT WINAPI VMR7MonitorConfig_GetMonitor(IVMRMonitorConfig *iface, VMR
struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
- return E_NOTIMPL;
+
+ if (pGUID)
+ pGUID->pGUID = NULL; /* default DirectDraw device */
+
+ return S_OK;
}
static HRESULT WINAPI VMR7MonitorConfig_SetDefaultMonitor(IVMRMonitorConfig *iface,
@@ -1326,7 +1330,7 @@ static HRESULT WINAPI VMR7MonitorConfig_SetDefaultMonitor(IVMRMonitorConfig *ifa
struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
- return E_NOTIMPL;
+ return S_OK;
}
static HRESULT WINAPI VMR7MonitorConfig_GetDefaultMonitor(IVMRMonitorConfig *iface, VMRGUID *pGUID)
@@ -1334,7 +1338,11 @@ static HRESULT WINAPI VMR7MonitorConfig_GetDefaultMonitor(IVMRMonitorConfig *ifa
struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
- return E_NOTIMPL;
+
+ if (pGUID)
+ pGUID->pGUID = NULL; /* default DirectDraw device */
+
+ return S_OK;
}
static HRESULT WINAPI VMR7MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig *iface,
@@ -1342,9 +1350,59 @@ static HRESULT WINAPI VMR7MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig *
DWORD *numdev)
{
struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
+ DISPLAY_DEVICEW device;
+ DWORD devnum, count;
+ DEVMODEW mode;
- FIXME("(%p/%p)->(%p, %u, %p) stub\n", iface, This, info, arraysize, numdev);
- return E_NOTIMPL;
+ FIXME("(%p/%p)->(%p, %u, %p) semi-stub\n", iface, This, info, arraysize, numdev);
+
+ if (!numdev)
+ return E_POINTER;
+
+ device.cb = sizeof(DISPLAY_DEVICEW);
+
+ /* return the number of available monitors if info == NULL */
+ if (info == NULL)
+ {
+ for (devnum = 0; EnumDisplayDevicesW(NULL, devnum, &device, 0); ++devnum);
+ *numdev = devnum;
+ return S_OK;
+ }
+
+ /* at least one entry */
+ if (arraysize == 0)
+ return E_INVALIDARG;
+
+ for (count = 0, devnum = 0; count < arraysize && EnumDisplayDevicesW(NULL, devnum, &device, 0); ++devnum)
+ {
+
+ mode.dmSize = sizeof(DEVMODEW);
+ mode.dmDriverExtra = 0;
+
+ if (!EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS, &mode, EDS_RAWMODE))
+ continue;
+
+ memset(info, 0, sizeof(VMRMONITORINFO));
+
+ info->guid.pGUID = NULL; /* default DirectDraw device */
+
+ info->rcMonitor.left = mode.u1.s2.dmPosition.x;
+ info->rcMonitor.top = mode.u1.s2.dmPosition.y;
+ info->rcMonitor.right = mode.u1.s2.dmPosition.x + mode.dmPelsWidth;
+ info->rcMonitor.bottom = mode.u1.s2.dmPosition.y + mode.dmPelsHeight;
+
+ info->hMon = 0; /* FIXME: return monitor handle */
+ info->dwFlags = (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? MONITORINFOF_PRIMARY : 0;
+
+ lstrcpynW(info->szDevice, device.DeviceName, sizeof(info->szDevice)/sizeof(WCHAR));
+ lstrcpynW(info->szDescription, device.DeviceString, sizeof(info->szDescription)/sizeof(WCHAR));
+
+ count++;
+ info++;
+ }
+
+ *numdev = count;
+ return S_OK;
}
static const IVMRMonitorConfigVtbl VMR7_MonitorConfig_Vtbl =
--
1.7.9.5

View File

@@ -0,0 +1,163 @@
From 4c261ca7ce6d73f0820106804797dcc7f0912b62 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 11 Nov 2013 00:18:31 +0100
Subject: quartz/tests: Add tests for IVMRMonitorConfig
---
dlls/quartz/tests/Makefile.in | 1 +
dlls/quartz/tests/monitorconfig.c | 131 +++++++++++++++++++++++++++++++++++++
2 files changed, 132 insertions(+)
create mode 100644 dlls/quartz/tests/monitorconfig.c
diff --git a/dlls/quartz/tests/Makefile.in b/dlls/quartz/tests/Makefile.in
index ae5fbac..94b2f44 100644
--- a/dlls/quartz/tests/Makefile.in
+++ b/dlls/quartz/tests/Makefile.in
@@ -8,6 +8,7 @@ C_SRCS = \
filtermapper.c \
memallocator.c \
misc.c \
+ monitorconfig.c \
referenceclock.c \
videorenderer.c
diff --git a/dlls/quartz/tests/monitorconfig.c b/dlls/quartz/tests/monitorconfig.c
new file mode 100644
index 0000000..3a18460
--- /dev/null
+++ b/dlls/quartz/tests/monitorconfig.c
@@ -0,0 +1,131 @@
+/*
+ * MonitorConfig unit tests for Quartz
+ *
+ * Copyright (C) 2013 Sebastian Lackner
+ *
+ * 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
+ */
+
+#define COBJMACROS
+
+#include "wine/test.h"
+#include "dshow.h"
+
+static void test_monitorconfig_setmonitor(void)
+{
+ HRESULT hr;
+ IUnknown *pVMR = NULL;
+ IVMRMonitorConfig *pMonitorConfig = NULL;
+ VMRGUID guid;
+
+ hr = CoCreateInstance(&CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IUnknown, (LPVOID*)&pVMR);
+ ok(hr == S_OK, "CoCreateInstance failed with %x.\n", hr);
+ ok(pVMR != NULL, "pVMR is NULL.\n");
+ if (!pVMR) goto out;
+
+ hr = IUnknown_QueryInterface(pVMR, &IID_IVMRMonitorConfig, (LPVOID*)&pMonitorConfig);
+ ok(hr == S_OK, "IUnknown_QueryInterface returned %x.\n", hr);
+ ok(pMonitorConfig != NULL, "pMonitorConfig is NULL.\n");
+ if (!pMonitorConfig) goto out;
+
+ memset(&guid, 0, sizeof(guid));
+ guid.pGUID = NULL; /* default DirectDraw device */
+ hr = IVMRMonitorConfig_SetMonitor(pMonitorConfig, &guid);
+ ok(hr == S_OK, "SetMonitor failed with %x.\n", hr);
+
+ memset(&guid, 255, sizeof(guid));
+ hr = IVMRMonitorConfig_GetMonitor(pMonitorConfig, &guid);
+ ok(hr == S_OK, "GetMonitor failed with %x.\n", hr);
+ ok(guid.pGUID == NULL, "GetMonitor returned guid.pGUID = %p, expected NULL.\n", guid.pGUID);
+
+ memset(&guid, 0, sizeof(guid));
+ guid.pGUID = NULL; /* default DirectDraw device */
+ hr = IVMRMonitorConfig_SetDefaultMonitor(pMonitorConfig, &guid);
+ ok(hr == S_OK, "SetDefaultMonitor failed with %x.\n", hr);
+
+ memset(&guid, 255, sizeof(guid));
+ hr = IVMRMonitorConfig_GetDefaultMonitor(pMonitorConfig, &guid);
+ ok(hr == S_OK, "GetDefaultMonitor failed with %x.\n", hr);
+ ok(guid.pGUID == NULL, "GetDefaultMonitor returned guid.pGUID = %p, expected NULL.\n", guid.pGUID);
+
+out:
+ if (pMonitorConfig) IVMRMonitorConfig_Release(pMonitorConfig);
+ if (pVMR) IUnknown_Release(pVMR);
+}
+
+static void test_monitorconfig_getavailablemonitors(void)
+{
+ HRESULT hr;
+ IUnknown *pVMR = NULL;
+ IVMRMonitorConfig *pMonitorConfig = NULL;
+ VMRMONITORINFO info[8];
+ DWORD numdev_total, numdev;
+
+ hr = CoCreateInstance(&CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IUnknown, (LPVOID*)&pVMR);
+ ok(hr == S_OK, "CoCreateInstance failed with %x.\n", hr);
+ ok(pVMR != NULL, "pVMR is NULL.\n");
+ if (!pVMR) goto out;
+
+ hr = IUnknown_QueryInterface(pVMR, &IID_IVMRMonitorConfig, (LPVOID*)&pMonitorConfig);
+ ok(hr == S_OK, "IUnknown_QueryInterface returned %x.\n", hr);
+ ok(pMonitorConfig != NULL, "pMonitorConfig is NULL.\n");
+ if (!pMonitorConfig) goto out;
+
+ /* call without any arguments */
+ hr = IVMRMonitorConfig_GetAvailableMonitors(pMonitorConfig, NULL, 0, NULL);
+ ok(hr == E_POINTER, "GetAvailableMonitors returned %x, expected E_POINTER.\n", hr);
+
+ hr = IVMRMonitorConfig_GetAvailableMonitors(pMonitorConfig, info, 0, &numdev_total);
+ ok(hr == E_INVALIDARG, "GetAvailableMonitors returned %x, expected E_INVALIDARG.\n", hr);
+
+ numdev_total = 0;
+ hr = IVMRMonitorConfig_GetAvailableMonitors(pMonitorConfig, NULL, 0, &numdev_total);
+ ok(hr == S_OK, "GetAvailableMonitors failed with %x.\n", hr);
+ ok(numdev_total > 0, "GetAvailableMonitors returned numdev_total = %d, expected > 0.\n", numdev_total);
+
+ if (numdev_total > 1)
+ {
+ /* return just the first monitor */
+ hr = IVMRMonitorConfig_GetAvailableMonitors(pMonitorConfig, info, 1, &numdev);
+ ok(hr == S_OK, "GetAvailableMonitors failed with %x.\n", hr);
+ ok(numdev == 1, "GetAvailableMonitors returned numdev = %d, expected 1.\n", numdev);
+ }
+
+ /* don't request information for more monitors than memory available */
+ if (numdev_total > sizeof(info)/sizeof(VMRMONITORINFO))
+ numdev_total = sizeof(info)/sizeof(VMRMONITORINFO);
+
+ hr = IVMRMonitorConfig_GetAvailableMonitors(pMonitorConfig, info, numdev_total, &numdev);
+ ok(hr == S_OK, "GetAvailableMonitors failed with %x.\n", hr);
+ ok(numdev == numdev_total, "GetAvailableMonitors returned numdev = %d, expected %d.\n", numdev, numdev_total);
+
+ /* TODO: Add test for content of info */
+
+out:
+ if (pMonitorConfig) IVMRMonitorConfig_Release(pMonitorConfig);
+ if (pVMR) IUnknown_Release(pVMR);
+}
+
+START_TEST(monitorconfig)
+{
+ CoInitialize(NULL);
+
+ test_monitorconfig_setmonitor();
+ test_monitorconfig_getavailablemonitors();
+
+ CoUninitialize();
+}
--
1.7.9.5

View File

@@ -0,0 +1,247 @@
From d4a65db7d42bcae783cf5357e4a38a3c27820047 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 26 Oct 2013 18:34:32 +0200
Subject: winex11: Implement additional XEMBED events
---
dlls/winex11.drv/event.c | 145 ++++++++++++++++++++++++++++++---------------
dlls/winex11.drv/window.c | 2 +-
2 files changed, 98 insertions(+), 49 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 4218949..64188bc 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -748,34 +748,22 @@ static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
else SetForegroundWindow( hwnd );
}
-
/**********************************************************************
- * X11DRV_FocusOut
- *
- * Note: only top-level windows get FocusOut events.
+ * focus_out
*/
-static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
-{
- XFocusChangeEvent *event = &xev->xfocus;
+ static void focus_out( Display *display , HWND hwnd )
+ {
HWND hwnd_tmp;
Window focus_win;
int revert;
XIC xic;
- TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
-
- if (event->detail == NotifyPointer)
- {
- if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
- return;
- }
- if (!hwnd) return;
if (ximInComposeMode) return;
x11drv_thread_data()->last_focus = hwnd;
if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
- if (root_window != DefaultRootWindow(event->display))
+ if (root_window != DefaultRootWindow(display))
{
if (hwnd == GetDesktopWindow()) reset_clipping_window();
return;
@@ -786,10 +774,10 @@ static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
/* don't reset the foreground window, if the window which is
getting the focus is a Wine window */
- XGetInputFocus( event->display, &focus_win, &revert );
+ XGetInputFocus( display, &focus_win, &revert );
if (focus_win)
{
- if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
+ if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
focus_win = 0;
}
@@ -805,6 +793,26 @@ static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
SetForegroundWindow( GetDesktopWindow() );
}
}
+ }
+
+/**********************************************************************
+ * X11DRV_FocusOut
+ *
+ * Note: only top-level windows get FocusOut events.
+ */
+static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
+{
+ XFocusChangeEvent *event = &xev->xfocus;
+
+ TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
+
+ if (event->detail == NotifyPointer)
+ {
+ if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
+ return;
+ }
+ if (!hwnd) return;
+ focus_out( event->display, hwnd );
}
@@ -940,6 +948,37 @@ static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data
return (ret == 2);
}
+/***********************************************************************
+ * reparent_notify
+ */
+static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
+{
+ HWND parent, old_parent;
+ DWORD style;
+
+ style = GetWindowLongW( hwnd, GWL_STYLE );
+ if (xparent == root_window)
+ {
+ parent = GetDesktopWindow();
+ style = (style & ~WS_CHILD) | WS_POPUP;
+ }
+ else
+ {
+ if (!(parent = create_foreign_window( display, xparent ))) return;
+ style = (style & ~WS_POPUP) | WS_CHILD;
+ }
+
+ ShowWindow( hwnd, SW_HIDE );
+ old_parent = SetParent( hwnd, parent );
+ SetWindowLongW( hwnd, GWL_STYLE, style );
+ SetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
+ ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
+
+ /* make old parent destroy itself if it no longer has children */
+ if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
+}
+
/***********************************************************************
* X11DRV_ReparentNotify
@@ -948,8 +987,6 @@ static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
{
XReparentEvent *event = &xev->xreparent;
struct x11drv_win_data *data;
- HWND parent, old_parent;
- DWORD style;
if (!(data = get_win_data( hwnd ))) return;
@@ -975,27 +1012,7 @@ static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
release_win_data( data );
- style = GetWindowLongW( hwnd, GWL_STYLE );
- if (event->parent == root_window)
- {
- parent = GetDesktopWindow();
- style = (style & ~WS_CHILD) | WS_POPUP;
- }
- else
- {
- if (!(parent = create_foreign_window( event->display, event->parent ))) return;
- style = (style & ~WS_POPUP) | WS_CHILD;
- }
-
- ShowWindow( hwnd, SW_HIDE );
- old_parent = SetParent( hwnd, parent );
- SetWindowLongW( hwnd, GWL_STYLE, style );
- SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
- ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
-
- /* make old parent destroy itself if it no longer has children */
- if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
+ reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
}
@@ -1594,22 +1611,54 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
*/
static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
{
- struct x11drv_win_data *data = get_win_data( hwnd );
-
- if (!data) return;
-
switch (event->data.l[1])
{
case XEMBED_EMBEDDED_NOTIFY:
- TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
- data->embedder = event->data.l[3];
+ {
+ struct x11drv_win_data *data = get_win_data( hwnd );
+ if (!data) break;
+
+ TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
+ data->embedder = event->data.l[3];
+
+ /* window has been marked as embedded before (e.g. systray) */
+ if (data->embedded)
+ {
+ release_win_data( data );
+ break;
+ }
+
+ make_window_embedded( data );
+ release_win_data( data );
+ reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
+ }
+ break;
+
+ case XEMBED_WINDOW_DEACTIVATE:
+ TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
+ focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
+ break;
+
+ case XEMBED_FOCUS_OUT:
+ TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
+ focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
break;
+
+ case XEMBED_MODALITY_ON:
+ TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
+ EnableWindow( hwnd, FALSE );
+ break;
+
+ case XEMBED_MODALITY_OFF:
+ TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
+ EnableWindow( hwnd, TRUE );
+ break;
+
default:
TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
hwnd, event->window, event->data.l[1], event->data.l[2] );
break;
}
- release_win_data( data );
}
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index a76e80d..e78f226 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -1137,7 +1137,7 @@ void make_window_embedded( struct x11drv_win_data *data )
data->embedded = TRUE;
data->managed = TRUE;
sync_window_style( data );
- set_xembed_flags( data, data->mapped ? XEMBED_MAPPED : 0 );
+ set_xembed_flags( data, (data->mapped || data->embedder) ? XEMBED_MAPPED : 0 );
}
--
1.7.9.5

View File

@@ -0,0 +1,165 @@
From 3db647fef4b506c88dfbe028271135945dbaec39 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 26 Oct 2013 18:39:07 +0200
Subject: winex11: Send XEMBED_REQUEST_FOCUS request for embedded windows
---
dlls/winex11.drv/event.c | 73 ++++++++++++++++++++++++++++++++-------------
dlls/winex11.drv/window.c | 16 ++++++++++
dlls/winex11.drv/x11drv.h | 1 +
3 files changed, 70 insertions(+), 20 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 64188bc..df27468 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -182,6 +182,32 @@ static inline void free_event_data( XEvent *event )
#endif
}
+
+/***********************************************************************
+ * xembed_request_focus
+ */
+static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.window = window;
+ xev.xclient.message_type = x11drv_atom(_XEMBED);
+ xev.xclient.serial = 0;
+ xev.xclient.display = display;
+ xev.xclient.send_event = True;
+ xev.xclient.format = 32;
+
+ xev.xclient.data.l[0] = timestamp;
+ xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent(display, window, False, NoEventMask, &xev);
+ XSync(display, False);
+}
+
/***********************************************************************
* X11DRV_register_event_handler
*
@@ -532,26 +558,37 @@ static inline BOOL can_activate_window( HWND hwnd )
/**********************************************************************
* set_input_focus
*
- * Try to force focus for non-managed windows.
+ * Try to force focus for embedded or non-managed windows.
*/
-static void set_input_focus( Display *display, Window window )
+static void set_input_focus( HWND hwnd )
{
XWindowChanges changes;
DWORD timestamp;
+ struct x11drv_win_data *data;
+ if (!(data = get_win_data( hwnd ))) return;
- if (!window) return;
+ if (data->whole_window && (data->embedder || !data->managed))
+ {
- if (EVENT_x11_time_to_win32_time(0))
- /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
- /* FIXME: this is not entirely correct */
- timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
- else
- timestamp = CurrentTime;
+ if (EVENT_x11_time_to_win32_time(0))
+ /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
+ /* FIXME: this is not entirely correct */
+ timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
+ else
+ timestamp = CurrentTime;
- /* Set X focus and install colormap */
- changes.stack_mode = Above;
- XConfigureWindow( display, window, CWStackMode, &changes );
- XSetInputFocus( display, window, RevertToParent, timestamp );
+ /* Set X focus and install colormap */
+ changes.stack_mode = Above;
+ XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
+
+ if (data->embedder)
+ xembed_request_focus( data->display, data->embedder, timestamp );
+ else
+ XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
+
+ }
+
+ release_win_data( data );
}
/**********************************************************************
@@ -904,7 +941,7 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
{
HWND hwndFocus = GetFocus();
if (hwndFocus && IsChild( hwnd, hwndFocus ))
- set_input_focus( data->display, data->whole_window );
+ set_input_focus( hwnd );
}
release_win_data( data );
}
@@ -1363,12 +1400,8 @@ void wait_for_withdrawn_state( HWND hwnd, BOOL set )
*/
void CDECL X11DRV_SetFocus( HWND hwnd )
{
- struct x11drv_win_data *data;
-
- if (!(hwnd = GetAncestor( hwnd, GA_ROOT ))) return;
- if (!(data = get_win_data( hwnd ))) return;
- if (!data->managed) set_input_focus( data->display, data->whole_window );
- release_win_data( data );
+ if (!(hwnd = get_ancestor_root_embedded( hwnd ))) return;
+ set_input_focus( hwnd );
}
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index e78f226..ebbfd45 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -1140,6 +1140,22 @@ void make_window_embedded( struct x11drv_win_data *data )
set_xembed_flags( data, (data->mapped || data->embedder) ? XEMBED_MAPPED : 0 );
}
+/***********************************************************************
+ * get_ancestor_root_embedded
+ */
+HWND get_ancestor_root_embedded( HWND hwnd )
+{
+ HWND parent;
+ if (!hwnd) return NULL;
+ for (;;)
+ {
+ parent = GetAncestor(hwnd, GA_PARENT);
+ if (!parent || parent == GetDesktopWindow() || (Window)GetPropA( parent, foreign_window_prop ))
+ break;
+ hwnd = parent;
+ }
+ return hwnd;
+}
/***********************************************************************
* X11DRV_window_to_X_rect
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 98386ce..71881fe 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -582,6 +582,7 @@ extern Window init_clip_window(void) DECLSPEC_HIDDEN;
extern void update_user_time( Time time ) DECLSPEC_HIDDEN;
extern void update_net_wm_states( struct x11drv_win_data *data ) DECLSPEC_HIDDEN;
extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN;
+extern HWND get_ancestor_root_embedded( HWND hwnd ) DECLSPEC_HIDDEN;
extern Window create_client_window( struct x11drv_win_data *data, const XVisualInfo *visual ) DECLSPEC_HIDDEN;
extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis ) DECLSPEC_HIDDEN;
extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN;
--
1.7.9.5

View File

@@ -0,0 +1,25 @@
From f9b183ba340f5dd0f8cf558c91e5a30bf2d09dfd Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 26 Oct 2013 18:40:07 +0200
Subject: winex11: Update gl_drawable for embedded windows
---
dlls/winex11.drv/window.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index ebbfd45..6a8d63b 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -2286,7 +2286,7 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags
sync_client_position( data, &old_client_rect, &old_whole_rect );
- if (!data->whole_window)
+ if (data->embedded || !data->whole_window)
{
release_win_data( data );
sync_gl_drawable( hwnd, visible_rect, rectClient );
--
1.7.9.5

View File

@@ -0,0 +1,25 @@
From b8177d6adbfeae337189d14a680025ac6277735b Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 26 Oct 2013 19:14:00 +0200
Subject: kernel32/tests: Fix tests compilation
---
dlls/kernel32/tests/directory.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/directory.c b/dlls/kernel32/tests/directory.c
index a3a9580..a7c30ee 100644
--- a/dlls/kernel32/tests/directory.c
+++ b/dlls/kernel32/tests/directory.c
@@ -645,7 +645,7 @@ done:
void init(void)
{
- HMODULE hmod = GetModuleHandle("advapi32.dll");
+ HMODULE hmod = GetModuleHandleA("advapi32.dll");
pGetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "GetNamedSecurityInfoA");
pAddAccessAllowedAceEx = (void *)GetProcAddress(hmod, "AddAccessAllowedAceEx");
--
1.7.9.5

View File

@@ -0,0 +1,44 @@
From 852f784dd4dd407d1183c01ce43c1a8e07231275 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 26 Oct 2013 19:39:33 +0200
Subject: kernel32: Change return value of stub SetNamedPipeHandleState to
TRUE
---
dlls/kernel32/sync.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index 5b7f810..331188f 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -1730,7 +1730,8 @@ BOOL WINAPI SetNamedPipeHandleState(
* runtime, and it slows down InstallShield a fair bit. */
WARN("stub: %p %p/%d %p %p\n",
hNamedPipe, lpMode, lpMode ? *lpMode : 0, lpMaxCollectionCount, lpCollectDataTimeout);
- return FALSE;
+ /* some programs expect this to return TRUE, and will abort otherwise */
+ return TRUE;
}
/***********************************************************************
@@ -1793,14 +1794,12 @@ BOOL WINAPI CallNamedPipeW(
mode = PIPE_READMODE_MESSAGE;
ret = SetNamedPipeHandleState(pipe, &mode, NULL, NULL);
- /* Currently SetNamedPipeHandleState() is a stub returning FALSE */
- if (ret) FIXME("Now that SetNamedPipeHandleState() is more than a stub, please update CallNamedPipeW\n");
- /*
+ /* Currently SetNamedPipeHandleState() is a stub returning TRUE */
if (!ret)
{
CloseHandle(pipe);
return FALSE;
- }*/
+ }
ret = TransactNamedPipe(pipe, lpInput, lpInputSize, lpOutput, lpOutputSize, lpBytesRead, NULL);
CloseHandle(pipe);
--
1.7.9.5

View File

@@ -0,0 +1,57 @@
From c80b095c919dcc976955f258fe177a2b24fd8dea Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 28 Oct 2013 00:39:17 +0100
Subject: winex11: Enable/disable windows when they are (un)mapped by foreign
applications
---
dlls/winex11.drv/event.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index df27468..9d958c0 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -929,6 +929,7 @@ static void X11DRV_Expose( HWND hwnd, XEvent *xev )
static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
{
struct x11drv_win_data *data;
+ BOOL is_embedded;
if (event->xany.window == x11drv_thread_data()->clip_window)
{
@@ -943,7 +944,12 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
if (hwndFocus && IsChild( hwnd, hwndFocus ))
set_input_focus( hwnd );
}
+
+ is_embedded = data->embedded;
release_win_data( data );
+
+ if (is_embedded)
+ EnableWindow( hwnd, TRUE );
}
@@ -952,7 +958,18 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
*/
static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
{
+ struct x11drv_win_data *data;
+ BOOL is_embedded;
+
if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
+
+ if (!(data = get_win_data( hwnd ))) return;
+
+ is_embedded = data->embedded;
+ release_win_data( data );
+
+ if (is_embedded)
+ EnableWindow( hwnd, FALSE );
}
--
1.7.9.5