From 63cb0f8b991677c137fcd3e25ba7b24407e5c12c Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Thu, 31 Dec 1998 15:43:48 +0000
Subject: [PATCH] Added change notifications. Added global handle support.

---
 include/server.h         | 30 ++++++++++++-----
 include/server/object.h  |  5 +++
 include/server/request.h |  3 ++
 server/Makefile.in       |  1 +
 server/change.c          | 70 ++++++++++++++++++++++++++++++++++++++++
 server/process.c         | 31 ++++++++++++++++--
 server/request.c         | 25 ++++++++++++--
 server/trace.c           | 26 ++++++++++++---
 8 files changed, 175 insertions(+), 16 deletions(-)
 create mode 100644 server/change.c

diff --git a/include/server.h b/include/server.h
index 106b9ac1807..4c0e9ee95c7 100644
--- a/include/server.h
+++ b/include/server.h
@@ -127,6 +127,9 @@ struct dup_handle_request
     int          inherit;      /* inherit flag */
     int          options;      /* duplicate options (see below) */
 };
+#define DUP_HANDLE_CLOSE_SOURCE  DUPLICATE_CLOSE_SOURCE
+#define DUP_HANDLE_SAME_ACCESS   DUPLICATE_SAME_ACCESS
+#define DUP_HANDLE_MAKE_GLOBAL   0x80000000  /* Not a Windows flag */
 struct dup_handle_reply
 {
     int          handle;       /* duplicated handle in dst process */
@@ -212,7 +215,7 @@ struct create_semaphore_request
     unsigned int initial;       /* initial count */
     unsigned int max;           /* maximum count */
     int          inherit;       /* inherit flag */
-    /* char name[] */
+    char         name[0];       /* semaphore name */
 };
 struct create_semaphore_reply
 {
@@ -235,10 +238,10 @@ struct release_semaphore_reply
 /* Open a named object (event, mutex, semaphore) */
 struct open_named_obj_request
 {
-    int          type;         /* object type (see below) */
-    unsigned int access;       /* wanted access rights */
-    int          inherit;      /* inherit flag */
-    /* char name[] */
+    int          type;          /* object type (see below) */
+    unsigned int access;        /* wanted access rights */
+    int          inherit;       /* inherit flag */
+    char         name[0];       /* object name */
 };
 enum open_named_obj { OPEN_EVENT, OPEN_MUTEX, OPEN_SEMAPHORE };
 
@@ -361,12 +364,25 @@ struct set_console_fd_request
 };
 
 
+/* Create a console */
+struct create_change_notification_request
+{
+    int          subtree;       /* watch all the subtree */
+    int          filter;        /* notification filter */
+};
+struct create_change_notification_reply
+{
+    int          handle;        /* handle to the change notification */
+};
+
+
 /* client-side functions */
 
 #ifndef __WINE_SERVER__
 
+#include "server/request.h"
+
 /* client communication functions */
-enum request;
 #define CHECK_LEN(len,wanted) \
   if ((len) == (wanted)) ; \
   else CLIENT_ProtocolError( __FUNCTION__ ": len %d != %d\n", (len), (wanted) );
@@ -380,8 +396,6 @@ struct _THDB;
 extern int CLIENT_NewThread( struct _THDB *thdb, int *thandle, int *phandle );
 extern int CLIENT_SetDebug( int level );
 extern int CLIENT_InitThread(void);
-extern int CLIENT_TerminateProcess( int handle, int exit_code );
-extern int CLIENT_TerminateThread( int handle, int exit_code );
 extern int CLIENT_CloseHandle( int handle );
 extern int CLIENT_DuplicateHandle( int src_process, int src_handle, int dst_process,
                                    int dst_handle, DWORD access, BOOL32 inherit, DWORD options );
diff --git a/include/server/object.h b/include/server/object.h
index f0c4938eeca..fc34f166f33 100644
--- a/include/server/object.h
+++ b/include/server/object.h
@@ -189,6 +189,11 @@ extern int create_console( int fd, struct object *obj[2] );
 extern int set_console_fd( int handle, int fd );
 
 
+/* change notification functions */
+
+extern struct object *create_change_notification( int subtree, int filter );
+
+
 extern int debug_level;
 
 #endif  /* __WINE_SERVER_OBJECT_H */
diff --git a/include/server/request.h b/include/server/request.h
index bd8ceaaed8b..993ae6e1e40 100644
--- a/include/server/request.h
+++ b/include/server/request.h
@@ -34,6 +34,7 @@ enum request
     REQ_CREATE_PIPE,
     REQ_CREATE_CONSOLE,
     REQ_SET_CONSOLE_FD,
+    REQ_CREATE_CHANGE_NOTIFICATION,
     REQ_NB_REQUESTS
 };
 
@@ -71,6 +72,7 @@ DECL_HANDLER(get_file_info);
 DECL_HANDLER(create_pipe);
 DECL_HANDLER(create_console);
 DECL_HANDLER(set_console_fd);
+DECL_HANDLER(create_change_notification);
 
 static const struct handler {
     void       (*handler)();
@@ -105,6 +107,7 @@ static const struct handler {
     { (void(*)())req_create_pipe, sizeof(struct create_pipe_request) },
     { (void(*)())req_create_console, sizeof(struct create_console_request) },
     { (void(*)())req_set_console_fd, sizeof(struct set_console_fd_request) },
+    { (void(*)())req_create_change_notification, sizeof(struct create_change_notification_request) },
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/Makefile.in b/server/Makefile.in
index ae2e19cbc6e..6ea40846ef7 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -6,6 +6,7 @@ VPATH     = @srcdir@
 MODULE    = server
 
 C_SRCS = \
+	change.c \
 	console.c \
 	event.c \
 	file.c \
diff --git a/server/change.c b/server/change.c
new file mode 100644
index 00000000000..6c7d38bb9f9
--- /dev/null
+++ b/server/change.c
@@ -0,0 +1,70 @@
+/*
+ * Server-side change notification management
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "winerror.h"
+#include "winnt.h"
+#include "server/thread.h"
+
+struct change
+{
+    struct object  obj;      /* object header */
+    int            subtree;  /* watch all the subtree */
+    int            filter;   /* notification filter */
+};
+
+static void change_dump( struct object *obj, int verbose );
+static int change_signaled( struct object *obj, struct thread *thread );
+static void change_destroy( struct object *obj );
+
+static const struct object_ops change_ops =
+{
+    change_dump,
+    add_queue,
+    remove_queue,
+    change_signaled,
+    no_satisfied,
+    no_read_fd,
+    no_write_fd,
+    no_flush,
+    change_destroy
+};
+
+
+struct object *create_change_notification( int subtree, int filter )
+{
+    struct change *change;
+    if (!(change = mem_alloc( sizeof(*change) ))) return NULL;
+    init_object( &change->obj, &change_ops, NULL );
+    change->subtree = subtree;
+    change->filter  = filter;
+    return &change->obj;
+}
+
+static void change_dump( struct object *obj, int verbose )
+{
+    struct change *change = (struct change *)obj;
+    assert( obj->ops == &change_ops );
+    printf( "Change notification sub=%d filter=%08x\n",
+            change->subtree, change->filter );
+}
+
+static int change_signaled( struct object *obj, struct thread *thread )
+{
+/*    struct change *change = (struct change *)obj;*/
+    assert( obj->ops == &change_ops );
+    return 0;  /* never signaled for now */
+}
+
+static void change_destroy( struct object *obj )
+{
+    struct change *change = (struct change *)obj;
+    assert( obj->ops == &change_ops );
+    free( change );
+}
diff --git a/server/process.c b/server/process.c
index 061218d232d..24dbde53a2e 100644
--- a/server/process.c
+++ b/server/process.c
@@ -25,6 +25,12 @@
 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
 #define RESERVED_ALL           (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
 
+/* global handle macros */
+#define HANDLE_OBFUSCATOR         0x544a4def
+#define HANDLE_IS_GLOBAL(h)       (((h) ^ HANDLE_OBFUSCATOR) < 0x10000)
+#define HANDLE_LOCAL_TO_GLOBAL(h) ((h) ^ HANDLE_OBFUSCATOR)
+#define HANDLE_GLOBAL_TO_LOCAL(h) ((h) ^ HANDLE_OBFUSCATOR)
+
 struct handle_entry
 {
     struct object *ptr;
@@ -49,6 +55,7 @@ struct process
 };
 
 static struct process *first_process;
+static struct process *initial_process;
 
 #define MIN_HANDLE_ENTRIES  32
 
@@ -94,6 +101,11 @@ struct process *create_process(void)
 
     if (first_process) first_process->prev = process;
     first_process = process;
+    if (!initial_process)
+    {
+        initial_process = process;
+        grab_object( initial_process ); /* so that we never free it */
+    }
 
     gettimeofday( &process->start_time, NULL );
     /* alloc a handle for the process itself */
@@ -106,6 +118,7 @@ static void process_destroy( struct object *obj )
 {
     struct process *process = (struct process *)obj;
     assert( obj->ops == &process_ops );
+    assert( process != initial_process );
 
     /* we can't have a thread remaining */
     assert( !process->thread_list );
@@ -288,6 +301,11 @@ static struct handle_entry *get_handle( struct process *process, int handle )
 {
     struct handle_entry *entry;
 
+    if (HANDLE_IS_GLOBAL(handle))
+    {
+        handle = HANDLE_GLOBAL_TO_LOCAL(handle);
+        process = initial_process;
+    }
     handle--;  /* handles start at 1 */
     if ((handle < 0) || (handle > process->handle_last)) goto error;
     entry = process->entries + handle;
@@ -370,6 +388,11 @@ int close_handle( struct process *process, int handle )
     struct handle_entry *entry;
     struct object *obj;
 
+    if (HANDLE_IS_GLOBAL(handle))
+    {
+        handle = HANDLE_GLOBAL_TO_LOCAL(handle);
+        process = initial_process;
+    }
     if (!(entry = get_handle( process, handle ))) return 0;
     if (entry->access & RESERVED_CLOSE_PROTECT) return 0;  /* FIXME: error code */
     obj = entry->ptr;
@@ -429,12 +452,16 @@ int set_handle_info( struct process *process, int handle, int mask, int flags )
 int duplicate_handle( struct process *src, int src_handle, struct process *dst,
                       int dst_handle, unsigned int access, int inherit, int options )
 {
+    int res;
     struct handle_entry *entry = get_handle( src, src_handle );
     if (!entry) return -1;
 
-    if (options & DUPLICATE_SAME_ACCESS) access = entry->access;
+    if (options & DUP_HANDLE_SAME_ACCESS) access = entry->access;
+    if (options & DUP_HANDLE_MAKE_GLOBAL) dst = initial_process;
     access &= ~RESERVED_ALL;
-    return alloc_specific_handle( dst, entry->ptr, dst_handle, access, inherit );
+    res = alloc_specific_handle( dst, entry->ptr, dst_handle, access, inherit );
+    if (options & DUP_HANDLE_MAKE_GLOBAL) res = HANDLE_LOCAL_TO_GLOBAL(res);
+    return res;
 }
 
 /* open a new handle to an existing object */
diff --git a/server/request.c b/server/request.c
index 4d15d3b6b93..4913cf19898 100644
--- a/server/request.c
+++ b/server/request.c
@@ -204,14 +204,19 @@ DECL_HANDLER(dup_handle)
 
     if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
     {
-        if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
+        if (req->options & DUP_HANDLE_MAKE_GLOBAL)
+        {
+            reply.handle = duplicate_handle( src, req->src_handle, NULL, -1,
+                                             req->access, req->inherit, req->options );
+        }
+        else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
         {
             reply.handle = duplicate_handle( src, req->src_handle, dst, req->dst_handle,
                                              req->access, req->inherit, req->options );
             release_object( dst );
         }
         /* close the handle no matter what happened */
-        if (req->options & DUPLICATE_CLOSE_SOURCE)
+        if (req->options & DUP_HANDLE_CLOSE_SOURCE)
             close_handle( src, req->src_handle );
         release_object( src );
     }
@@ -531,3 +536,19 @@ DECL_HANDLER(set_console_fd)
     set_console_fd( req->handle, fd );
     send_reply( current, -1, 0 );
 }
+
+/* create a change notification */
+DECL_HANDLER(create_change_notification)
+{
+    struct object *obj;
+    struct create_change_notification_reply reply = { -1 };
+
+    if ((obj = create_change_notification( req->subtree, req->filter )))
+    {
+        reply.handle = alloc_handle( current->process, obj,
+                                     STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
+        release_object( obj );
+    }
+    send_reply( current, -1, 1, &reply, sizeof(reply) );
+}
+
diff --git a/server/trace.c b/server/trace.c
index 199f8a677aa..1bc83ca8bc4 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -172,8 +172,9 @@ static int dump_create_semaphore_request( struct create_semaphore_request *req,
 {
     printf( " initial=%08x,", req->initial );
     printf( " max=%08x,", req->max );
-    printf( " inherit=%d", req->inherit );
-    return (int)sizeof(*req);
+    printf( " inherit=%d,", req->inherit );
+    printf( " name=\"%.*s\"", len - (int)sizeof(*req), (char *)(req+1) );
+    return len;
 }
 
 static int dump_create_semaphore_reply( struct create_semaphore_reply *req, int len )
@@ -199,8 +200,9 @@ static int dump_open_named_obj_request( struct open_named_obj_request *req, int
 {
     printf( " type=%d,", req->type );
     printf( " access=%08x,", req->access );
-    printf( " inherit=%d", req->inherit );
-    return (int)sizeof(*req);
+    printf( " inherit=%d,", req->inherit );
+    printf( " name=\"%.*s\"", len - (int)sizeof(*req), (char *)(req+1) );
+    return len;
 }
 
 static int dump_open_named_obj_reply( struct open_named_obj_reply *req, int len )
@@ -321,6 +323,19 @@ static int dump_set_console_fd_request( struct set_console_fd_request *req, int
     return (int)sizeof(*req);
 }
 
+static int dump_create_change_notification_request( struct create_change_notification_request *req, int len )
+{
+    printf( " subtree=%d,", req->subtree );
+    printf( " filter=%d", req->filter );
+    return (int)sizeof(*req);
+}
+
+static int dump_create_change_notification_reply( struct create_change_notification_reply *req, int len )
+{
+    printf( " handle=%d", req->handle );
+    return (int)sizeof(*req);
+}
+
 struct dumper
 {
     int (*dump_req)( void *data, int len );
@@ -387,6 +402,8 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] =
       (void(*)())dump_create_console_reply },
     { (int(*)(void *,int))dump_set_console_fd_request,
       (void(*)())0 },
+    { (int(*)(void *,int))dump_create_change_notification_request,
+      (void(*)())dump_create_change_notification_reply },
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] =
@@ -420,6 +437,7 @@ static const char * const req_names[REQ_NB_REQUESTS] =
     "create_pipe",
     "create_console",
     "set_console_fd",
+    "create_change_notification",
 };
 
 void trace_request( enum request req, void *data, int len, int fd )
-- 
GitLab