mirror of
https://abf.rosa.ru/djam/wine2.git
synced 2025-02-23 16:42:54 +00:00
Update to 1.7.8
This commit is contained in:
parent
a21ccaf060
commit
4bfe38b885
14 changed files with 1941 additions and 1282 deletions
7
.abf.yml
7
.abf.yml
|
@ -1,3 +1,6 @@
|
|||
removed_sources:
|
||||
wine-1.7.4.tar.bz2: f3ccfb7a6870311f2d85b1cbbcc1f87df409bb6a
|
||||
sources:
|
||||
wine-1.5.28.tar.bz2: bc543b215dd25efc7d76c6ffa99672c6e3d15d61
|
||||
wine-1.5.28.tar.bz2.sign: 699c8d362d01bf22eb684fac7349ff0635f677d0
|
||||
wine-1.7.4.tar.bz2.sign: d60f74a3babd7a0cb5e2a9fd6a0e36e7b06e8768
|
||||
wine-1.7.8.tar.bz2: 86de5dd5120e4e3cf2a19b0822250131664b006a
|
||||
wine-1.7.8.tar.bz2.sign: cdaed82e0dc851d4412a3042e9c0ebefeeee2390
|
||||
|
|
|
@ -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
|
||||
|
440
0002-server-Implement-an-interface-change-notification-ob.patch
Normal file
440
0002-server-Implement-an-interface-change-notification-ob.patch
Normal file
|
@ -0,0 +1,440 @@
|
|||
From aa5c2e5b4bf9716af3ea2065a3d3de10c840f59b Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Mon, 18 Nov 2013 17:22:04 -0700
|
||||
Subject: server: Implement an interface change notification object.
|
||||
|
||||
---
|
||||
server/event.c | 13 +++
|
||||
server/named_pipe.c | 13 ---
|
||||
server/object.h | 1 +
|
||||
server/sock.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
4 files changed, 301 insertions(+), 15 deletions(-)
|
||||
|
||||
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..4e41b72 100644
|
||||
--- a/server/sock.c
|
||||
+++ b/server/sock.c
|
||||
@@ -44,11 +44,17 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#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 +113,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 +127,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 +163,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 +533,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 +635,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 +672,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 +961,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
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
From b3156dc253a94f9414a04569181728ec43608f2a Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Mon, 18 Nov 2013 17:22:14 -0700
|
||||
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..b6da0e7 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 card.\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
|
||||
|
499
0004-server-Store-and-return-security-attributes-with-ext.patch
Normal file
499
0004-server-Store-and-return-security-attributes-with-ext.patch
Normal file
|
@ -0,0 +1,499 @@
|
|||
From 78a5ebb94f3717bedd77f7c096e8fce1e9a640d1 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Mon, 18 Nov 2013 18:12:05 -0700
|
||||
Subject: server: Store and return security attributes with extended file
|
||||
attributes.
|
||||
|
||||
---
|
||||
configure.ac | 6 ++
|
||||
dlls/advapi32/tests/security.c | 25 +++---
|
||||
server/change.c | 11 ++-
|
||||
server/fd.c | 68 +++++++++++++++-
|
||||
server/file.c | 176 +++++++++++++++++++++++++++++++++++++++-
|
||||
server/file.h | 5 +-
|
||||
6 files changed, 269 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 98a73f2..bb03667 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -71,6 +71,7 @@ AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthrea
|
||||
AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)]))
|
||||
AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF]))
|
||||
AC_ARG_WITH(v4l, AS_HELP_STRING([--without-v4l],[do not use v4l1 (v4l support)]))
|
||||
+AC_ARG_WITH(xattr, AS_HELP_STRING([--without-xattr],[do not use xattr (security attributes support)]))
|
||||
AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]),
|
||||
[if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi])
|
||||
AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]),
|
||||
@@ -666,6 +667,11 @@ AC_CHECK_HEADERS([libprocstat.h],,,
|
||||
#include <sys/socket.h>
|
||||
#endif])
|
||||
|
||||
+if test "x$with_xattr" != "xno"
|
||||
+then
|
||||
+ AC_CHECK_HEADERS(attr/xattr.h)
|
||||
+fi
|
||||
+
|
||||
dnl **** Check for working dll ****
|
||||
|
||||
AC_SUBST(dlldir,"\${libdir}/wine")
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index fe31b5c..7d28c05 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -3088,10 +3088,10 @@ static void test_CreateDirectoryA(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);
|
||||
}
|
||||
@@ -3100,10 +3100,10 @@ static void test_CreateDirectoryA(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);
|
||||
}
|
||||
@@ -3277,7 +3277,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",
|
||||
@@ -3288,8 +3288,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 */,
|
||||
@@ -3943,7 +3942,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",
|
||||
@@ -3954,7 +3953,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/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 cceb8ad..9ac9188 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
|
||||
@@ -237,7 +241,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))
|
||||
@@ -424,9 +428,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;
|
||||
@@ -443,9 +607,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;
|
||||
@@ -575,6 +741,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 493d30b..721c087 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
|
||||
|
180
0005-ntdll-Inherit-security-attributes-from-parent-direct.patch
Normal file
180
0005-ntdll-Inherit-security-attributes-from-parent-direct.patch
Normal file
|
@ -0,0 +1,180 @@
|
|||
From 5e49f53a4bd591e67c9b7c4fdaf46933e319f9aa Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Mon, 18 Nov 2013 18:15:20 -0700
|
||||
Subject: ntdll: Inherit security attributes from parent directories.
|
||||
|
||||
---
|
||||
dlls/advapi32/tests/security.c | 40 ++++++++++++++++++-
|
||||
dlls/ntdll/file.c | 85 +++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 123 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
|
||||
index 7d28c05..a8d136b 100644
|
||||
--- a/dlls/advapi32/tests/security.c
|
||||
+++ b/dlls/advapi32/tests/security.c
|
||||
@@ -3013,10 +3013,11 @@ static void test_CreateDirectoryA(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;
|
||||
|
||||
@@ -3108,6 +3109,43 @@ static void test_CreateDirectoryA(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 1de2c61..8948bb7 100644
|
||||
--- a/dlls/ntdll/file.c
|
||||
+++ b/dlls/ntdll/file.c
|
||||
@@ -103,6 +103,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.
|
||||
@@ -161,10 +236,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
|
||||
|
|
@ -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
|
||||
|
25
0007-winex11-Update-gl_drawable-for-embedded-windows.patch
Normal file
25
0007-winex11-Update-gl_drawable-for-embedded-windows.patch
Normal 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
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
From 90f7d78cf1ee2bf4329b298cb24e0e5145637557 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Fri, 22 Nov 2013 18:54:18 +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 767c003..f39b922 100644
|
||||
--- a/dlls/winex11.drv/event.c
|
||||
+++ b/dlls/winex11.drv/event.c
|
||||
@@ -922,6 +922,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)
|
||||
{
|
||||
@@ -936,7 +937,12 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
|
||||
if (hwndFocus && IsChild( hwnd, hwndFocus ))
|
||||
set_input_focus( data );
|
||||
}
|
||||
+
|
||||
+ is_embedded = data->embedded;
|
||||
release_win_data( data );
|
||||
+
|
||||
+ if (is_embedded)
|
||||
+ EnableWindow( hwnd, TRUE );
|
||||
}
|
||||
|
||||
|
||||
@@ -945,8 +951,19 @@ 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 = FALSE;
|
||||
+
|
||||
+ 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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
From 4347b37128afcd1878a0f993a058fe147f219982 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Fri, 22 Nov 2013 18:40:59 +0100
|
||||
Subject: quartz/tests: Add tests for IVMRMonitorConfig and IVMRMonitorConfig9
|
||||
interface
|
||||
|
||||
---
|
||||
dlls/quartz/tests/videorenderer.c | 275 ++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 254 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/dlls/quartz/tests/videorenderer.c b/dlls/quartz/tests/videorenderer.c
|
||||
index ce1ac29..e3a4fa2 100644
|
||||
--- a/dlls/quartz/tests/videorenderer.c
|
||||
+++ b/dlls/quartz/tests/videorenderer.c
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "dshow.h"
|
||||
+#include "initguid.h"
|
||||
+#include "d3d9.h"
|
||||
+#include "vmr9.h"
|
||||
|
||||
#define QI_SUCCEED(iface, riid, ppv) hr = IUnknown_QueryInterface(iface, &riid, (LPVOID*)&ppv); \
|
||||
ok(hr == S_OK, "IUnknown_QueryInterface returned %x\n", hr); \
|
||||
@@ -32,28 +35,17 @@
|
||||
ok(hr == num, "IUnknown_Release should return %d, got %d\n", num, hr); \
|
||||
}
|
||||
|
||||
-static IUnknown *pVideoRenderer = NULL;
|
||||
-
|
||||
-static int create_video_renderer(void)
|
||||
+static const WCHAR *memchrW( const WCHAR *ptr, WCHAR ch, size_t n )
|
||||
{
|
||||
- HRESULT hr;
|
||||
-
|
||||
- hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
|
||||
- &IID_IUnknown, (LPVOID*)&pVideoRenderer);
|
||||
- return (hr == S_OK && pVideoRenderer != NULL);
|
||||
-}
|
||||
-
|
||||
-static void release_video_renderer(void)
|
||||
-{
|
||||
- HRESULT hr;
|
||||
-
|
||||
- hr = IUnknown_Release(pVideoRenderer);
|
||||
- ok(hr == 0, "IUnknown_Release failed with %x\n", hr);
|
||||
+ const WCHAR *end;
|
||||
+ for (end = ptr + n; ptr < end; ptr++) if (*ptr == ch) return ptr;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
static void test_query_interface(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
+ IUnknown *pVideoRenderer = NULL;
|
||||
IBaseFilter *pBaseFilter = NULL;
|
||||
IBasicVideo *pBasicVideo = NULL;
|
||||
IDirectDrawVideo *pDirectDrawVideo = NULL;
|
||||
@@ -64,6 +56,15 @@ static void test_query_interface(void)
|
||||
IQualProp *pQualProp = NULL;
|
||||
IVideoWindow *pVideoWindow = NULL;
|
||||
|
||||
+ hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
|
||||
+ &IID_IUnknown, (LPVOID*)&pVideoRenderer);
|
||||
+ ok(hr != S_OK || pVideoRenderer != NULL, "CoCreateInstance returned S_OK, but pVideoRenderer is NULL.\n");
|
||||
+ if (hr != S_OK || !pVideoRenderer)
|
||||
+ {
|
||||
+ skip("VideoRenderer is not available, skipping QI test.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
QI_SUCCEED(pVideoRenderer, IID_IBaseFilter, pBaseFilter);
|
||||
RELEASE_EXPECT(pBaseFilter, 1);
|
||||
QI_SUCCEED(pVideoRenderer, IID_IBasicVideo, pBasicVideo);
|
||||
@@ -84,6 +85,8 @@ static void test_query_interface(void)
|
||||
RELEASE_EXPECT(pMediaPosition, 1);
|
||||
QI_SUCCEED(pVideoRenderer, IID_IVideoWindow, pVideoWindow);
|
||||
RELEASE_EXPECT(pVideoWindow, 1);
|
||||
+
|
||||
+ RELEASE_EXPECT(pVideoRenderer, 0);
|
||||
}
|
||||
|
||||
static void test_pin(IPin *pin)
|
||||
@@ -104,18 +107,28 @@ static void test_pin(IPin *pin)
|
||||
|
||||
static void test_basefilter(void)
|
||||
{
|
||||
+ IUnknown *pVideoRenderer = NULL;
|
||||
IEnumPins *pin_enum = NULL;
|
||||
IBaseFilter *base = NULL;
|
||||
IPin *pins[2];
|
||||
ULONG ref;
|
||||
HRESULT hr;
|
||||
|
||||
+ hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
|
||||
+ &IID_IUnknown, (LPVOID*)&pVideoRenderer);
|
||||
+ ok(hr != S_OK || pVideoRenderer != NULL, "CoCreateInstance returned S_OK, but pVideoRenderer is NULL.\n");
|
||||
+ if (hr != S_OK || !pVideoRenderer)
|
||||
+ {
|
||||
+ skip("VideoRenderer is not available, skipping BaseFilter test.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
IUnknown_QueryInterface(pVideoRenderer, &IID_IBaseFilter, (void **)&base);
|
||||
if (base == NULL)
|
||||
{
|
||||
/* test_query_interface handles this case */
|
||||
skip("No IBaseFilter\n");
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
hr = IBaseFilter_EnumPins(base, NULL);
|
||||
@@ -147,19 +160,239 @@ static void test_basefilter(void)
|
||||
ref = IEnumPins_Release(pin_enum);
|
||||
ok(ref == 0, "ref is %u and not 0!\n", ref);
|
||||
|
||||
- IBaseFilter_Release(base);
|
||||
+out:
|
||||
+ if (base) IBaseFilter_Release(base);
|
||||
+ RELEASE_EXPECT(pVideoRenderer, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_monitorconfig7(void)
|
||||
+{
|
||||
+ HRESULT hr;
|
||||
+ IUnknown *pVMR7 = NULL;
|
||||
+ IVMRMonitorConfig *pMonitorConfig = NULL;
|
||||
+ VMRGUID guid;
|
||||
+ VMRMONITORINFO info[8];
|
||||
+ DWORD numdev_total, numdev;
|
||||
+ GUID max_guid;
|
||||
+ RECT max_rect;
|
||||
+
|
||||
+ hr = CoCreateInstance(&CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER,
|
||||
+ &IID_IUnknown, (LPVOID*)&pVMR7);
|
||||
+ ok(hr != S_OK || pVMR7 != NULL, "CoCreateInstance returned S_OK, but pVMR7 is NULL.\n");
|
||||
+ if (hr != S_OK || !pVMR7)
|
||||
+ {
|
||||
+ skip("VideoMixingRenderer7 is not available, skipping MonitorConfig7 test.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ hr = IUnknown_QueryInterface(pVMR7, &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;
|
||||
+
|
||||
+ hr = IVMRMonitorConfig_SetMonitor(pMonitorConfig, NULL);
|
||||
+ ok(hr == E_POINTER, "SetMonitor returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig_GetMonitor(pMonitorConfig, NULL);
|
||||
+ ok(hr == E_POINTER, "GetMonitor returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig_SetDefaultMonitor(pMonitorConfig, NULL);
|
||||
+ ok(hr == E_POINTER, "SetDefaultMonitor returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig_GetDefaultMonitor(pMonitorConfig, NULL);
|
||||
+ ok(hr == E_POINTER, "GetDefaultMonitor returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ /* check if its possible to provide a buffer which is too small for all entries */
|
||||
+ if (numdev_total > 1)
|
||||
+ {
|
||||
+ 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(info[0]))
|
||||
+ numdev_total = sizeof(info)/sizeof(info[0]);
|
||||
+ memset(info, 255, sizeof(info));
|
||||
+ 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);
|
||||
+
|
||||
+ memset(&max_guid, 255, sizeof(max_guid));
|
||||
+ memset(&max_rect, 255, sizeof(max_rect));
|
||||
+
|
||||
+ /* check that result is filled out, we do not check if the values actually make any sense */
|
||||
+ while (numdev--)
|
||||
+ {
|
||||
+ ok(info[numdev].guid.pGUID == NULL || info[numdev].guid.pGUID == &info[numdev].guid.GUID,
|
||||
+ "GetAvailableMonitors returned info[%d].guid.pGUID = %p, expected NULL or %p.\n", numdev, info[numdev].guid.pGUID, &info[numdev].guid.GUID);
|
||||
+ ok(info[numdev].guid.pGUID != &info[numdev].guid.GUID || memcmp(&info[numdev].guid.GUID, &max_guid, sizeof(max_guid)) != 0,
|
||||
+ "GetAvailableMonitors returned info[%d].GUID = {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}, expected any other value.\n", numdev);
|
||||
+ ok(memcmp(&info[numdev].rcMonitor, &max_rect, sizeof(max_rect)) != 0,
|
||||
+ "GetAvailableMonitors returned info[%d].rcMonitor = {-1, -1, -1, -1}, expected any other value.\n", numdev);
|
||||
+ ok(info[numdev].hMon != (HMONITOR)0 && info[numdev].hMon != (HMONITOR)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].hMon = %p, expected != 0 and != -1.\n", numdev, info[numdev].hMon);
|
||||
+ ok(info[numdev].dwFlags != (DWORD)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].dwFlags = -1, expected != -1.\n", numdev);
|
||||
+ ok(memchrW(info[numdev].szDevice, 0, sizeof(info[numdev].szDevice)/sizeof(WCHAR)) != NULL,
|
||||
+ "GetAvailableMonitors returned info[%d].szDevice without null-termination.\n", numdev);
|
||||
+ ok(memchrW(info[numdev].szDescription, 0, sizeof(info[numdev].szDescription)/sizeof(WCHAR)) != NULL,
|
||||
+ "GetAvailableMonitors returned info[%d].szDescription without null-termination.\n", numdev);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ if (pMonitorConfig) IVMRMonitorConfig_Release(pMonitorConfig);
|
||||
+ RELEASE_EXPECT(pVMR7, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_monitorconfig9(void)
|
||||
+{
|
||||
+ HRESULT hr;
|
||||
+ IUnknown *pVMR9 = NULL;
|
||||
+ IVMRMonitorConfig9 *pMonitorConfig = NULL;
|
||||
+ UINT uDev;
|
||||
+ VMR9MonitorInfo info[8];
|
||||
+ DWORD numdev_total, numdev;
|
||||
+ RECT max_rect;
|
||||
+
|
||||
+ hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
|
||||
+ &IID_IUnknown, (LPVOID*)&pVMR9);
|
||||
+ ok(hr != S_OK || pVMR9 != NULL, "CoCreateInstance returned S_OK, but pVMR9 is NULL.\n");
|
||||
+ if (hr != S_OK || !pVMR9)
|
||||
+ {
|
||||
+ skip("VideoMixingRenderer9 is not available, skipping MonitorConfig9 test.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ hr = IUnknown_QueryInterface(pVMR9, &IID_IVMRMonitorConfig9, (LPVOID*)&pMonitorConfig);
|
||||
+ ok(hr == S_OK, "IUnknown_QueryInterface returned %x.\n", hr);
|
||||
+ ok(pMonitorConfig != NULL, "pMonitorConfig is NULL.\n");
|
||||
+ if (!pMonitorConfig) goto out;
|
||||
+
|
||||
+ hr = IVMRMonitorConfig9_GetMonitor(pMonitorConfig, NULL);
|
||||
+ ok(hr == E_POINTER, "GetMonitor returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig9_GetDefaultMonitor(pMonitorConfig, NULL);
|
||||
+ ok(hr == E_POINTER, "GetDefaultMonitor returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig9_SetMonitor(pMonitorConfig, 0);
|
||||
+ ok(hr == S_OK, "SetMonitor failed with %x.\n", hr);
|
||||
+
|
||||
+ uDev = 0xdeadbeef;
|
||||
+ hr = IVMRMonitorConfig9_GetMonitor(pMonitorConfig, &uDev);
|
||||
+ ok(hr == S_OK, "GetMonitor failed with %x.\n", hr);
|
||||
+ ok(uDev == 0, "GetMonitor returned uDev = %d, expected 0.\n", uDev);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig9_SetDefaultMonitor(pMonitorConfig, 0);
|
||||
+ ok(hr == S_OK, "SetDefaultMonitor failed with %x.\n", hr);
|
||||
+
|
||||
+ uDev = 0xdeadbeef;
|
||||
+ hr = IVMRMonitorConfig9_GetDefaultMonitor(pMonitorConfig, &uDev);
|
||||
+ ok(hr == S_OK, "GetDefaultMonitor failed with %x.\n", hr);
|
||||
+ ok(uDev == 0, "GetDefaultMonitor returned uDev = %d, expected 0.\n", uDev);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig9_GetAvailableMonitors(pMonitorConfig, NULL, 0, NULL);
|
||||
+ ok(hr == E_POINTER, "GetAvailableMonitors returned %x, expected E_POINTER.\n", hr);
|
||||
+
|
||||
+ hr = IVMRMonitorConfig9_GetAvailableMonitors(pMonitorConfig, info, 0, &numdev_total);
|
||||
+ ok(hr == E_INVALIDARG, "GetAvailableMonitors returned %x, expected E_INVALIDARG.\n", hr);
|
||||
+
|
||||
+ numdev_total = 0;
|
||||
+ hr = IVMRMonitorConfig9_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);
|
||||
+
|
||||
+ /* check if its possible to provide a buffer which is too small for all entries */
|
||||
+ if (numdev_total > 1)
|
||||
+ {
|
||||
+ hr = IVMRMonitorConfig9_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);
|
||||
+ }
|
||||
+
|
||||
+ if (numdev_total > sizeof(info)/sizeof(info[0]))
|
||||
+ numdev_total = sizeof(info)/sizeof(info[0]);
|
||||
+ memset(info, 255, sizeof(info));
|
||||
+ hr = IVMRMonitorConfig9_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);
|
||||
+
|
||||
+ memset(&max_rect, 255, sizeof(max_rect));
|
||||
+
|
||||
+ /* check that result is filled out, we do not check if the values actually make any sense */
|
||||
+ while (numdev--)
|
||||
+ {
|
||||
+ ok(info[numdev].uDevID != (UINT)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].uDevID = -1, expected != -1.\n", numdev);
|
||||
+ ok(memcmp(&info[numdev].rcMonitor, &max_rect, sizeof(max_rect)) != 0,
|
||||
+ "GetAvailableMonitors returned info[%d].rcMonitor = {-1, -1, -1, -1}, expected any other value.\n", numdev);
|
||||
+ ok(info[numdev].hMon != (HMONITOR)0 && info[numdev].hMon != (HMONITOR)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].hMon = %p, expected != 0 and != -1.\n", numdev, info[numdev].hMon);
|
||||
+ ok(info[numdev].dwFlags != (DWORD)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].dwFlags = -1, expected != -1.\n", numdev);
|
||||
+ ok(memchrW(info[numdev].szDevice, 0, sizeof(info[numdev].szDevice)/sizeof(WCHAR)) != NULL,
|
||||
+ "GetAvailableMonitors returned info[%d].szDevice without null-termination.\n", numdev);
|
||||
+ ok(memchrW(info[numdev].szDescription, 0, sizeof(info[numdev].szDescription)/sizeof(WCHAR)) != NULL,
|
||||
+ "GetAvailableMonitors returned info[%d].szDescription without null-termination.\n", numdev);
|
||||
+ ok(info[numdev].dwVendorId != (DWORD)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].dwVendorId = -1, expected != -1.\n", numdev);
|
||||
+ ok(info[numdev].dwDeviceId != (DWORD)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].dwDeviceId = -1, expected != -1.\n", numdev);
|
||||
+ ok(info[numdev].dwSubSysId != (DWORD)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].dwSubSysId = -1, expected != -1.\n", numdev);
|
||||
+ ok(info[numdev].dwRevision != (DWORD)-1,
|
||||
+ "GetAvailableMonitors returned info[%d].dwRevision = -1, expected != -1.\n", numdev);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ if (pMonitorConfig) IVMRMonitorConfig9_Release(pMonitorConfig);
|
||||
+ RELEASE_EXPECT(pVMR9, 0);
|
||||
}
|
||||
|
||||
START_TEST(videorenderer)
|
||||
{
|
||||
CoInitialize(NULL);
|
||||
- if (!create_video_renderer())
|
||||
- return;
|
||||
|
||||
+ /* Video Renderer tests */
|
||||
test_query_interface();
|
||||
test_basefilter();
|
||||
|
||||
- release_video_renderer();
|
||||
+ /* Video Mixing Renderer 7 tests */
|
||||
+ test_monitorconfig7();
|
||||
+
|
||||
+ /* Video Mixing Renderer 9 tests */
|
||||
+ test_monitorconfig9();
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
--
|
||||
1.7.9.5
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From c586d47aabf8741b8526579868c691e77ff5f7c8 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Thu, 21 Nov 2013 03:37:31 +0100
|
||||
Subject: quartz: Workaround Silverlight problems when multiple monitors are
|
||||
found
|
||||
|
||||
---
|
||||
dlls/quartz/vmr9.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c
|
||||
index 31f3f8e..20da5b9 100644
|
||||
--- a/dlls/quartz/vmr9.c
|
||||
+++ b/dlls/quartz/vmr9.c
|
||||
@@ -1440,7 +1440,7 @@ static HRESULT WINAPI VMR7MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig *
|
||||
|
||||
args.info7 = info;
|
||||
args.info9 = NULL;
|
||||
- args.arraysize = arraysize;
|
||||
+ args.arraysize = 1; /* only return first entry */
|
||||
args.numdev = 0;
|
||||
EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args);
|
||||
|
||||
@@ -1540,7 +1540,7 @@ static HRESULT WINAPI VMR9MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig9
|
||||
|
||||
args.info7 = NULL;
|
||||
args.info9 = info;
|
||||
- args.arraysize = arraysize;
|
||||
+ args.arraysize = 1; /* only return first entry */
|
||||
args.numdev = 0;
|
||||
EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args);
|
||||
|
||||
--
|
||||
1.7.9.5
|
||||
|
|
@ -1,2 +1,5 @@
|
|||
addFilter("E: executable-in-library-package")
|
||||
addFilter("E: non-versioned-file-in-library-package")
|
||||
addFilter("E: incoherent-version-in-name")
|
||||
# Intentional - linking to Linux libc would cause symbol clashes with MS libc
|
||||
addFilter("E: library-not-linked-against-libc")
|
||||
|
|
Loading…
Add table
Reference in a new issue