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

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*~

62
debian/changelog vendored Normal file
View File

@ -0,0 +1,62 @@
wine-compholio (1.7.6-1) unstable; urgency=low
* Work around a build problem with Wine 1.7.6.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Tue, 12 Nov 2013 14:16:16 -0700
wine-compholio (1.7.6) unstable; urgency=low
* Rebased VMR7 patches against upstream Wine 1.7.6.
* Rebased SIO_ADDRESS_LIST_CHANGE patches against upstream Wine 1.7.6.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Sun, 10 Nov 2013 17:26:30 -0700
wine-compholio (1.7.5-1) unstable; urgency=low
* Included new patch to fix running TestOut under Silverlight.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Thu, 07 Nov 2013 11:18:23 -0700
wine-compholio (1.7.5) unstable; urgency=low
* Rebased changes against upstream Wine 1.7.5.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Wed, 30 Oct 2013 08:05:51 -0600
wine-compholio (1.7.4-2) unstable; urgency=low
* Updated XEmbed patches from Sebastian Lackner.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Mon, 28 Oct 2013 10:00:43 -0600
wine-compholio (1.7.4-1) unstable; urgency=low
* Fix an issue with Ubuntu 13.10 post-install behavior.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Sun, 13 Oct 2013 15:13:48 -0600
wine-compholio (1.7.4) unstable; urgency=low
* Rebased changes against upstream Wine 1.7.4.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Sat, 12 Oct 2013 13:30:33 -0600
wine-compholio (1.7.3) unstable; urgency=low
* Removed patches already included in upstream Wine 1.7.3.
* Rebased ACL extended attributes patch against upstream Wine 1.7.3.
* Update SIO_ADDRESS_LIST_CHANGE patches to new server-based method.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Thu, 03 Oct 2013 15:16:26 -0600
wine-compholio (1.7.2) unstable; urgency=low
* Rebased changes against upstream Wine 1.7.2.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Mon, 30 Sep 2013 12:21:43 -0600
wine-compholio (1.7.1) unstable; urgency=low
* Rebased changes against upstream Wine 1.7.1.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Mon, 30 Sep 2013 11:42:34 -0600
wine-compholio (1.7.0-7) unstable; urgency=low
* Updated all changed patches and backported upstream commits.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Mon, 30 Sep 2013 11:41:43 -0600
wine-compholio (1.7.0-6) unstable; urgency=low
* Included fix for Watchever from Andreas Loibl.
-- Erich E. Hoover <ehoover@mines.edu> Fri, 06 Sep 2013 16:33:33 -0600
wine-compholio (1.7.0-5) unstable; urgency=low
* Updated patches for LOVEFiLM from Sebastian Lackner and Michael Müller.
-- Erich E. Hoover <ehoover@mines.edu> Fri, 06 Sep 2013 16:33:33 -0600
wine-compholio (1.7.0-4) unstable; urgency=low
* Hopefully fixed build script problem.
-- Erich E. Hoover <ehoover@mines.edu> Tue, 27 Aug 2013 09:51:15 -0600
wine-compholio (1.7.0-3) unstable; urgency=low
* Added D3D acceleration fix from Michael Müller.
-- Erich E. Hoover <ehoover@mines.edu> Fri, 16 Apr 2010 12:20:00 -0600

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
7

0
debian/conffiles vendored Normal file
View File

136
debian/control vendored Normal file
View File

@ -0,0 +1,136 @@
Source: wine-compholio
Section: otherosfs
Priority: optional
Maintainer: Erich E. Hoover <ehoover@mines.edu>
XSBC-Original-Maintainer: Scott Ritchie <scottritchie@ubuntu.com>
Build-Depends: autotools-dev,
autoconf,
bind9-host,
bison,
debhelper (>= 7),
docbook-to-man,
docbook-utils,
docbook-xsl,
flex,
fontforge,
gcc-4.5 | gcc-4.7 | ubuntu-desktop (<< 1.207),
gcc-4.5-multilib [amd64] | ubuntu-desktop (<< 1.207) [amd64],
gcc-multilib [amd64],
gettext,
ia32-libs [amd64],
ia32-libs-dev [amd64] | ubuntu-desktop (<< 1.267) [amd64],
ia32-libs-multiarch [amd64] | ubuntu-desktop (<< 1.267) [amd64],
lib32asound2-dev [amd64],
lib32ncurses5-dev [amd64],
lib32z1-dev [amd64],
libacl1-dev,
libasound2-dev [i386 lpia],
libc6-dev-i386 [amd64],
libcapi20-dev,
libcups2-dev,
libdbus-1-dev,
libesd0 | libesd-alsa0,
libesd0-dev,
libfontconfig1-dev | libfontconfig-dev,
libfreetype6-dev,
libgif-dev | libungif4-dev,
libgl1-mesa-dev | nvidia-glx-dev | fglrx-driver-dev | libgl-dev,
libglu1-mesa-dev | libglu-dev,
libgnutls-dev,
libgphoto2-dev | libgphoto2-6-dev | libgphoto2-2-dev (>= 2.4.6),
libgphoto2port-dev | ubuntu-desktop (>= 1.245) | debian-edu-config,
libgsm1-dev,
libgstreamer-plugins-base0.10-dev,
libgstreamer0.10-dev,
libice-dev,
libjpeg-dev,
liblcms1-dev, liblcms-dev,
libldap2-dev, libldap-dev,
libmpg123-dev,
libncurses5-dev [i386] | libncurses-dev [i386],
libopenal-dev (>= 1:1.12) | ubuntu-desktop (<< 1.207),
libpng12-dev,
libssl-dev,
libstdc++6-4.5-dev | libstdc++-dev,
libtiff4-dev,
libv4l-dev [i386],
libx11-dev,
libxcomposite-dev,
libxcursor-dev,
libxext-dev,
libxi-dev,
libxinerama-dev,
libxml2-dev,
libxrandr-dev,
libxrender-dev,
libxslt1-dev,
libxt-dev,
libxxf86vm-dev,
linux-kernel-headers,
linux-libc-dev,
prelink [i386 amd64],
quilt (>= 0.46-7~),
sharutils,
unixodbc-dev,
x11proto-xinerama-dev
Standards-Version: 3.9.2
Package: wine-compholio
Architecture: i386
Multi-Arch: foreign
Pre-Depends: dpkg (>= 1.14.12ubuntu3), ${misc:Pre-Depends}
Depends: ${shlibs:Depends},
libasound2-plugins,
libncurses5
Recommends: gettext,
libcapi20-3,
libcups2,
libdbus-1-3,
libfontconfig1 | libfontconfig,
libfreetype6,
libgif4,
libgnutls26,
libgphoto2-6 | libgphoto2-2 (>= 2.4.6),
libgphoto2-port0 (>= 2.4.6),
libjpeg8,
libopenal1 (>= 1:1.12),
libosmesa6,
libpng12-0,
libpulse0,
libsane,
libssl1.0.0,
libtiff4,
libv4l-0,
libxcomposite1,
libxcursor1,
libxi6,
libxinerama1,
libxrandr2,
libxrender1,
libxslt1.1,
libxt6,
libxxf86vm1,
unixodbc
Provides: wine-compholio
Section: otherosfs
Priority: optional
Description: The Compholio Edition is a special build of the popular Wine software
with patches representing my current staging tree for Wine.
Currently these patches fix:
* Netflix on Firefox hangs with loading bar at 100% (Bug 31993).
* Netflix on Firefox fails with Internet Connection Problem when loading bar is
at 99% (Bug 31858).
.
Microsoft Windows Compatibility Layer (Binary Emulator and Library)
Wine is a compatibility layer for running Windows applications on Linux.
Applications are run at full speed without the need of cpu emulation. Wine
does not require Microsoft Windows, however it can use native system dll
files in place of its own if they are available.
.
This package includes a program loader for running unmodified Windows executables
as well as the Wine project's free version of the Windows API for running programs
ported from Windows.
.
This package is based on a recent Wine beta. While many more applications will
work, there may be some loss of functionality compared with the stable release
provided by the regular wine package.

23
debian/postinst vendored Executable file
View File

@ -0,0 +1,23 @@
#!/bin/sh -e
if [ "$1" = "upgrade" ] ; then
if ps -C wineserver > /dev/null && test -d /var/lib/update-notifier/user.d/ ; then
cp -f /usr/share/wine/wineserver-restart-required.update-notifier /var/lib/update-notifier/user.d/wineserver-restart-required
fi
fi
service procps start || /etc/init.d/procps restart
# Automatically added by dh_installmime
if [ "$1" = "configure" ] && [ -x "`which update-mime 2>/dev/null`" ]; then
update-mime
fi
# End automatically added section
# Automatically added by dh_makeshlibs
if [ "$1" = "configure" ]; then
ldconfig
fi
# End automatically added section

10
debian/postrm vendored Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
set -e
# Automatically added by dh_installmime
if which update-mime >/dev/null 2>&1; then update-mime; fi
# End automatically added section
# Automatically added by dh_makeshlibs
if [ "$1" = "remove" ]; then
ldconfig
fi
# End automatically added section

9
debian/prerm vendored Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh -e
if [ "$1" = "remove" ] ; then
if [ -x /usr/sbin/update-binfmts ]; then
/usr/sbin/update-binfmts --package wine --remove wine /usr/bin/wine || true
fi
fi

151
debian/rules vendored Executable file
View File

@ -0,0 +1,151 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
else
CROSS= --build $(DEB_BUILD_GNU_TYPE)
endif
# Apparently it's important to have an empty LDFLAGS, see:
# http://www.winehq.org/pipermail/wine-bugs/2007-July/062505.html
# For Wine 1.1.44 it's also important not to compile at -O0
LDFLAGS =
CFLAGS = -Wall -g -O2
# On amd64 the 32-bit libraries are in lib32 instead of lib
ifeq ($(DEB_BUILD_ARCH), amd64)
CONFFLAGS += --libdir=\$${prefix}/lib32
endif
# Use gcc-4.5 if it's available
ifeq ($(shell which gcc-4.5),)
CC = gcc
else
CC = gcc-4.5
endif
# Support passing of parallel=<n> in build options
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
MAKEFLAGS += -j$(NUMJOBS)
endif
configure:
# Unpack the original Wine version
tar -xjvf wine-*.tar.bz2
mv wine-*/* .
rm wine-*/.* || true
rm wine-*.tar.bz2
rmdir wine-*
config.status: configure
dh_testdir
# Add here commands to configure the package.
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
endif
# Apply our patches to Wine
for FILE in `ls $(CURDIR)/patches`; do \
patch -N -p0 --strip=1 < $(CURDIR)/patches/$$FILE || exit 1; \
done
# Update the configure script
autoreconf
# Configure
CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/opt/wine-compholio --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info $(CONFFLAGS)
build: build-stamp
build-stamp: config.status
dh_testdir
# Add here commands to compile the package.
$(MAKE) depend
$(MAKE) $(MAKEFLAGS)
#docbook-to-man debian/wine-compholio.sgml > wine-compholio.1
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
[ ! -f Makefile ] || $(MAKE) distclean
rm -f config.sub config.guess
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
dh_installdirs
# Add here commands to install the package into debian/wine-compholio.
$(MAKE) DESTDIR=$(CURDIR)/debian/wine-compholio install
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
# dh_installchangelogs ChangeLog
dh_installdocs
dh_installexamples
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_python
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
dh_makeshlibs
dh_installdeb
ifeq ($(DEB_BUILD_ARCH), amd64)
dh_gencontrol -- -V"shlibs:Depends= ia32-libs (>= 1.6), lib32asound2 (>> 1.0.14), libc6-i386 (>= 2.6-1), lib32nss-mdns (>= 0.10-3)"
else
LD_LIBRARY_PATH="$(CURDIR)/debian/wine-compholio/opt/wine-compholio/lib:${LD_LIBRARY_PATH}" dh_shlibdeps -L wine-compholio -l debian/wine-compholio/opt/wine-compholio/lib
dh_gencontrol
endif
dh_md5sums
dh_builddeb -- -Z lzma
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

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