Implemented makepath, rand() returns correct range, fixed fputc.
[wine] / server / request.c
1 /*
2  * Server-side request handling
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <sys/uio.h>
15 #include <unistd.h>
16
17 #include "winerror.h"
18 #include "winnt.h"
19 #include "winbase.h"
20 #include "wincon.h"
21 #define WANT_REQUEST_HANDLERS
22 #include "server.h"
23 #include "server/request.h"
24 #include "server/process.h"
25 #include "server/thread.h"
26
27 /* check that the string is NULL-terminated and that the len is correct */
28 #define CHECK_STRING(func,str,len) \
29   do { if (((str)[(len)-1] || strlen(str) != (len)-1)) \
30          fatal_protocol_error( "%s: invalid string '%.*s'\n", (func), (len), (str) ); \
31      } while(0)
32  
33 struct thread *current = NULL;  /* thread handling the current request */
34
35 /* complain about a protocol error and terminate the client connection */
36 static void fatal_protocol_error( const char *err, ... )
37 {
38     va_list args;
39
40     va_start( args, err );
41     fprintf( stderr, "Protocol error:%p: ", current );
42     vfprintf( stderr, err, args );
43     va_end( args );
44     remove_client( current->client_fd, -2 );
45 }
46
47 /* call a request handler */
48 void call_req_handler( struct thread *thread, enum request req,
49                        void *data, int len, int fd )
50 {
51     const struct handler *handler = &req_handlers[req];
52     char *ptr;
53
54     current = thread;
55     if ((req < 0) || (req >= REQ_NB_REQUESTS))
56     {
57         fatal_protocol_error( "unknown request %d\n", req );
58         return;
59     }
60
61     if (len < handler->min_size)
62     {
63         fatal_protocol_error( "req %d bad length %d < %d)\n", req, len, handler->min_size );
64         return;
65     }
66
67     /* now call the handler */
68     if (current)
69     {
70         CLEAR_ERROR();
71         if (debug_level) trace_request( req, data, len, fd );
72     }
73     len -= handler->min_size;
74     ptr = (char *)data + handler->min_size;
75     handler->handler( data, ptr, len, fd );
76     current = NULL;
77 }
78
79 /* handle a client timeout (unused for now) */
80 void call_timeout_handler( struct thread *thread )
81 {
82     current = thread;
83     if (debug_level) trace_timeout();
84     CLEAR_ERROR();
85     thread_timeout();
86     current = NULL;
87 }
88
89 /* a thread has been killed */
90 void call_kill_handler( struct thread *thread, int exit_code )
91 {
92     /* must be reentrant WRT call_req_handler */
93     struct thread *old_current = current;
94     current = thread;
95     if (current)
96     {
97         if (debug_level) trace_kill( exit_code );
98         thread_killed( current, exit_code );
99     }
100     current = (old_current != thread) ? old_current : NULL;
101 }
102
103
104 /* create a new process */
105 DECL_HANDLER(new_process)
106 {
107     struct new_process_reply reply;
108     struct process *process;
109
110     if ((process = create_process( req )))
111     {
112         reply.pid    = process;
113         reply.handle = alloc_handle( current->process, process,
114                                      PROCESS_ALL_ACCESS, req->inherit );
115         release_object( process );
116     }
117     else
118     {
119         reply.handle = -1;
120         reply.pid    = NULL;
121     }
122     send_reply( current, -1, 1, &reply, sizeof(reply) );
123 }
124
125 /* create a new thread */
126 DECL_HANDLER(new_thread)
127 {
128     struct new_thread_reply reply;
129     int new_fd;
130
131     if ((new_fd = dup(fd)) != -1)
132     {
133         reply.tid = create_thread( new_fd, req->pid, req->suspend,
134                                    req->inherit, &reply.handle );
135         if (!reply.tid) close( new_fd );
136     }
137     else
138         SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
139
140     send_reply( current, -1, 1, &reply, sizeof(reply) );
141 }
142
143 /* initialize a new process */
144 DECL_HANDLER(init_process)
145 {
146     struct init_process_reply reply;
147     if (current->state != RUNNING)
148     {
149         fatal_protocol_error( "init_process: init_thread not called yet\n" );
150         return;
151     }
152     if (!get_process_init_info( current->process, &reply ))
153     {
154         fatal_protocol_error( "init_process: called twice\n" );
155         return;
156     }
157     send_reply( current, -1, 1, &reply, sizeof(reply) );
158 }
159
160 /* initialize a new thread */
161 DECL_HANDLER(init_thread)
162 {
163     struct init_thread_reply reply;
164
165     if (current->state != STARTING)
166     {
167         fatal_protocol_error( "init_thread: already running\n" );
168         return;
169     }
170     current->state    = RUNNING;
171     current->unix_pid = req->unix_pid;
172     if (current->suspend > 0)
173         kill( current->unix_pid, SIGSTOP );
174     reply.pid = current->process;
175     reply.tid = current;
176     send_reply( current, -1, 1, &reply, sizeof(reply) );
177 }
178
179 /* set the debug level */
180 DECL_HANDLER(set_debug)
181 {
182     debug_level = req->level;
183     /* Make sure last_req is initialized */
184     current->last_req = REQ_SET_DEBUG;
185     CLEAR_ERROR();
186     send_reply( current, -1, 0 );
187 }
188
189 /* terminate a process */
190 DECL_HANDLER(terminate_process)
191 {
192     struct process *process;
193
194     if ((process = get_process_from_handle( req->handle, PROCESS_TERMINATE )))
195     {
196         kill_process( process, req->exit_code );
197         release_object( process );
198     }
199     if (current) send_reply( current, -1, 0 );
200 }
201
202 /* terminate a thread */
203 DECL_HANDLER(terminate_thread)
204 {
205     struct thread *thread;
206
207     if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
208     {
209         kill_thread( thread, req->exit_code );
210         release_object( thread );
211     }
212     if (current) send_reply( current, -1, 0 );
213 }
214
215 /* close a handle */
216 DECL_HANDLER(close_handle)
217 {
218     close_handle( current->process, req->handle );
219     send_reply( current, -1, 0 );
220 }
221
222 /* get information about a handle */
223 DECL_HANDLER(get_handle_info)
224 {
225     struct get_handle_info_reply reply;
226     reply.flags = set_handle_info( current->process, req->handle, 0, 0 );
227     send_reply( current, -1, 1, &reply, sizeof(reply) );
228 }
229
230 /* set a handle information */
231 DECL_HANDLER(set_handle_info)
232 {
233     set_handle_info( current->process, req->handle, req->mask, req->flags );
234     send_reply( current, -1, 0 );
235 }
236
237 /* duplicate a handle */
238 DECL_HANDLER(dup_handle)
239 {
240     struct dup_handle_reply reply = { -1 };
241     struct process *src, *dst;
242
243     if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
244     {
245         if (req->options & DUP_HANDLE_MAKE_GLOBAL)
246         {
247             reply.handle = duplicate_handle( src, req->src_handle, NULL,
248                                              req->access, req->inherit, req->options );
249         }
250         else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
251         {
252             reply.handle = duplicate_handle( src, req->src_handle, dst,
253                                              req->access, req->inherit, req->options );
254             release_object( dst );
255         }
256         /* close the handle no matter what happened */
257         if (req->options & DUP_HANDLE_CLOSE_SOURCE)
258             close_handle( src, req->src_handle );
259         release_object( src );
260     }
261     send_reply( current, -1, 1, &reply, sizeof(reply) );
262 }
263
264 /* fetch information about a process */
265 DECL_HANDLER(get_process_info)
266 {
267     struct process *process;
268     struct get_process_info_reply reply = { 0, 0, 0 };
269
270     if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
271     {
272         get_process_info( process, &reply );
273         release_object( process );
274     }
275     send_reply( current, -1, 1, &reply, sizeof(reply) );
276 }
277
278 /* set information about a process */
279 DECL_HANDLER(set_process_info)
280 {
281     struct process *process;
282
283     if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION )))
284     {
285         set_process_info( process, req );
286         release_object( process );
287     }
288     send_reply( current, -1, 0 );
289 }
290
291 /* fetch information about a thread */
292 DECL_HANDLER(get_thread_info)
293 {
294     struct thread *thread;
295     struct get_thread_info_reply reply = { 0, 0 };
296
297     if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
298     {
299         get_thread_info( thread, &reply );
300         release_object( thread );
301     }
302     send_reply( current, -1, 1, &reply, sizeof(reply) );
303 }
304
305 /* set information about a thread */
306 DECL_HANDLER(set_thread_info)
307 {
308     struct thread *thread;
309
310     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_INFORMATION )))
311     {
312         set_thread_info( thread, req );
313         release_object( thread );
314     }
315     send_reply( current, -1, 0 );
316 }
317
318 /* suspend a thread */
319 DECL_HANDLER(suspend_thread)
320 {
321     struct thread *thread;
322     struct suspend_thread_reply reply = { -1 };
323     if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
324     {
325         reply.count = suspend_thread( thread );
326         release_object( thread );
327     }
328     send_reply( current, -1, 1, &reply, sizeof(reply) );
329     
330 }
331
332 /* resume a thread */
333 DECL_HANDLER(resume_thread)
334 {
335     struct thread *thread;
336     struct resume_thread_reply reply = { -1 };
337     if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
338     {
339         reply.count = resume_thread( thread );
340         release_object( thread );
341     }
342     send_reply( current, -1, 1, &reply, sizeof(reply) );
343     
344 }
345
346 /* queue an APC for a thread */
347 DECL_HANDLER(queue_apc)
348 {
349     struct thread *thread;
350     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
351     {
352         thread_queue_apc( thread, req->func, req->param );
353         release_object( thread );
354     }
355     send_reply( current, -1, 0 );
356 }
357
358 /* open a handle to a process */
359 DECL_HANDLER(open_process)
360 {
361     struct open_process_reply reply = { -1 };
362     struct process *process = get_process_from_id( req->pid );
363     if (process)
364     {
365         reply.handle = alloc_handle( current->process, process,
366                                      req->access, req->inherit );
367         release_object( process );
368     }
369     send_reply( current, -1, 1, &reply, sizeof(reply) );
370 }
371
372 /* select on a handle list */
373 DECL_HANDLER(select)
374 {
375     if (len != req->count * sizeof(int))
376         fatal_protocol_error( "select: bad length %d for %d handles\n",
377                               len, req->count );
378     sleep_on( current, req->count, (int *)data, req->flags, req->timeout );
379 }
380
381 /* create an event */
382 DECL_HANDLER(create_event)
383 {
384     struct create_event_reply reply = { -1 };
385     struct object *obj;
386     char *name = (char *)data;
387     if (!len) name = NULL;
388     else CHECK_STRING( "create_event", name, len );
389
390     obj = create_event( name, req->manual_reset, req->initial_state );
391     if (obj)
392     {
393         reply.handle = alloc_handle( current->process, obj, EVENT_ALL_ACCESS, req->inherit );
394         release_object( obj );
395     }
396     send_reply( current, -1, 1, &reply, sizeof(reply) );
397 }
398
399 /* do an event operation */
400 DECL_HANDLER(event_op)
401 {
402     switch(req->op)
403     {
404     case PULSE_EVENT:
405         pulse_event( req->handle );
406         break;
407     case SET_EVENT:
408         set_event( req->handle );
409         break;
410     case RESET_EVENT:
411         reset_event( req->handle );
412         break;
413     default:
414         fatal_protocol_error( "event_op: invalid operation %d\n", req->op );
415     }
416     send_reply( current, -1, 0 );
417 }
418
419 /* create a mutex */
420 DECL_HANDLER(create_mutex)
421 {
422     struct create_mutex_reply reply = { -1 };
423     struct object *obj;
424     char *name = (char *)data;
425     if (!len) name = NULL;
426     else CHECK_STRING( "create_mutex", name, len );
427
428     obj = create_mutex( name, req->owned );
429     if (obj)
430     {
431         reply.handle = alloc_handle( current->process, obj, MUTEX_ALL_ACCESS, req->inherit );
432         release_object( obj );
433     }
434     send_reply( current, -1, 1, &reply, sizeof(reply) );
435 }
436
437 /* release a mutex */
438 DECL_HANDLER(release_mutex)
439 {
440     if (release_mutex( req->handle )) CLEAR_ERROR();
441     send_reply( current, -1, 0 );
442 }
443
444 /* create a semaphore */
445 DECL_HANDLER(create_semaphore)
446 {
447     struct create_semaphore_reply reply = { -1 };
448     struct object *obj;
449     char *name = (char *)data;
450     if (!len) name = NULL;
451     else CHECK_STRING( "create_semaphore", name, len );
452
453     obj = create_semaphore( name, req->initial, req->max );
454     if (obj)
455     {
456         reply.handle = alloc_handle( current->process, obj, SEMAPHORE_ALL_ACCESS, req->inherit );
457         release_object( obj );
458     }
459     send_reply( current, -1, 1, &reply, sizeof(reply) );
460 }
461
462 /* release a semaphore */
463 DECL_HANDLER(release_semaphore)
464 {
465     struct release_semaphore_reply reply;
466     if (release_semaphore( req->handle, req->count, &reply.prev_count )) CLEAR_ERROR();
467     send_reply( current, -1, 1, &reply, sizeof(reply) );
468 }
469
470 /* open a handle to a named object (event, mutex, semaphore) */
471 DECL_HANDLER(open_named_obj)
472 {
473     struct open_named_obj_reply reply;
474     char *name = (char *)data;
475     if (!len) name = NULL;
476     else CHECK_STRING( "open_named_obj", name, len );
477
478     switch(req->type)
479     {
480     case OPEN_EVENT:
481         reply.handle = open_event( req->access, req->inherit, name );
482         break;
483     case OPEN_MUTEX:
484         reply.handle = open_mutex( req->access, req->inherit, name );
485         break;
486     case OPEN_SEMAPHORE:
487         reply.handle = open_semaphore( req->access, req->inherit, name );
488         break;
489     case OPEN_MAPPING:
490         reply.handle = open_mapping( req->access, req->inherit, name );
491         break;
492     default:
493         fatal_protocol_error( "open_named_obj: invalid type %d\n", req->type );
494     }
495     send_reply( current, -1, 1, &reply, sizeof(reply) );
496 }
497
498 /* create a file */
499 DECL_HANDLER(create_file)
500 {
501     struct create_file_reply reply = { -1 };
502     struct object *obj;
503     char *name = (char *)data;
504     if (!len) name = NULL;
505     else CHECK_STRING( "create_file", name, len );
506
507     if ((obj = create_file( fd, name, req->access,
508                             req->sharing, req->create, req->attrs )) != NULL)
509     {
510         reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
511         release_object( obj );
512     }
513     send_reply( current, -1, 1, &reply, sizeof(reply) );
514 }
515
516 /* get a Unix fd to read from a file */
517 DECL_HANDLER(get_read_fd)
518 {
519     struct object *obj;
520     int read_fd;
521
522     if ((obj = get_handle_obj( current->process, req->handle, GENERIC_READ, NULL )))
523     {
524         read_fd = obj->ops->get_read_fd( obj );
525         release_object( obj );
526     }
527     else read_fd = -1;
528     send_reply( current, read_fd, 0 );
529 }
530
531 /* get a Unix fd to write to a file */
532 DECL_HANDLER(get_write_fd)
533 {
534     struct object *obj;
535     int write_fd;
536
537     if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
538     {
539         write_fd = obj->ops->get_write_fd( obj );
540         release_object( obj );
541     }
542     else write_fd = -1;
543     send_reply( current, write_fd, 0 );
544 }
545
546 /* set a file current position */
547 DECL_HANDLER(set_file_pointer)
548 {
549     struct set_file_pointer_reply reply = { req->low, req->high };
550     set_file_pointer( req->handle, &reply.low, &reply.high, req->whence );
551     send_reply( current, -1, 1, &reply, sizeof(reply) );
552 }
553
554 /* truncate (or extend) a file */
555 DECL_HANDLER(truncate_file)
556 {
557     truncate_file( req->handle );
558     send_reply( current, -1, 0 );
559 }
560
561 /* flush a file buffers */
562 DECL_HANDLER(flush_file)
563 {
564     struct object *obj;
565
566     if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
567     {
568         obj->ops->flush( obj );
569         release_object( obj );
570     }
571     send_reply( current, -1, 0 );
572 }
573
574 /* set a file access and modification times */
575 DECL_HANDLER(set_file_time)
576 {
577     set_file_time( req->handle, req->access_time, req->write_time );
578     send_reply( current, -1, 0 );
579 }
580
581 /* get a file information */
582 DECL_HANDLER(get_file_info)
583 {
584     struct object *obj;
585     struct get_file_info_reply reply;
586
587     if ((obj = get_handle_obj( current->process, req->handle, 0, NULL )))
588     {
589         obj->ops->get_file_info( obj, &reply );
590         release_object( obj );
591     }
592     send_reply( current, -1, 1, &reply, sizeof(reply) );
593 }
594
595 /* lock a region of a file */
596 DECL_HANDLER(lock_file)
597 {
598     struct file *file;
599
600     if ((file = get_file_obj( current->process, req->handle, 0 )))
601     {
602         file_lock( file, req->offset_high, req->offset_low,
603                    req->count_high, req->count_low );
604         release_object( file );
605     }
606     send_reply( current, -1, 0 );
607 }
608
609
610 /* unlock a region of a file */
611 DECL_HANDLER(unlock_file)
612 {
613     struct file *file;
614
615     if ((file = get_file_obj( current->process, req->handle, 0 )))
616     {
617         file_unlock( file, req->offset_high, req->offset_low,
618                      req->count_high, req->count_low );
619         release_object( file );
620     }
621     send_reply( current, -1, 0 );
622 }
623
624
625 /* create an anonymous pipe */
626 DECL_HANDLER(create_pipe)
627 {
628     struct create_pipe_reply reply = { -1, -1 };
629     struct object *obj[2];
630     if (create_pipe( obj ))
631     {
632         reply.handle_read = alloc_handle( current->process, obj[0],
633                                           STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_READ,
634                                           req->inherit );
635         if (reply.handle_read != -1)
636         {
637             reply.handle_write = alloc_handle( current->process, obj[1],
638                                                STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
639                                                req->inherit );
640             if (reply.handle_write == -1)
641                 close_handle( current->process, reply.handle_read );
642         }
643         release_object( obj[0] );
644         release_object( obj[1] );
645     }
646     send_reply( current, -1, 1, &reply, sizeof(reply) );
647 }
648
649 /* allocate a console for the current process */
650 DECL_HANDLER(alloc_console)
651 {
652     alloc_console( current->process );
653     send_reply( current, -1, 0 );
654 }
655
656 /* free the console of the current process */
657 DECL_HANDLER(free_console)
658 {
659     free_console( current->process );
660     send_reply( current, -1, 0 );
661 }
662
663 /* open a handle to the process console */
664 DECL_HANDLER(open_console)
665 {
666     struct object *obj;
667     struct open_console_reply reply = { -1 };
668     if ((obj = get_console( current->process, req->output )))
669     {
670         reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
671         release_object( obj );
672     }
673     send_reply( current, -1, 1, &reply, sizeof(reply) );
674 }
675
676 /* set info about a console (output only) */
677 DECL_HANDLER(set_console_info)
678 {
679     char *name = (char *)data;
680     if (!len) name = NULL;
681     else CHECK_STRING( "set_console_info", name, len );
682     set_console_info( req->handle, req, name );
683     send_reply( current, -1, 0 );
684 }
685
686 /* get info about a console (output only) */
687 DECL_HANDLER(get_console_info)
688 {
689     struct get_console_info_reply reply;
690     const char *title;
691     get_console_info( req->handle, &reply, &title );
692     send_reply( current, -1, 2, &reply, sizeof(reply),
693                 title, title ? strlen(title)+1 : 0 );
694 }
695
696 /* set a console fd */
697 DECL_HANDLER(set_console_fd)
698 {
699     set_console_fd( req->handle, fd, req->pid );
700     send_reply( current, -1, 0 );
701 }
702
703 /* get a console mode (input or output) */
704 DECL_HANDLER(get_console_mode)
705 {
706     struct get_console_mode_reply reply;
707     get_console_mode( req->handle, &reply.mode );
708     send_reply( current, -1, 1, &reply, sizeof(reply) );
709 }
710
711 /* set a console mode (input or output) */
712 DECL_HANDLER(set_console_mode)
713 {
714     set_console_mode( req->handle, req->mode );
715     send_reply( current, -1, 0 );
716 }
717
718 /* add input records to a console input queue */
719 DECL_HANDLER(write_console_input)
720 {
721     struct write_console_input_reply reply;
722     INPUT_RECORD *records = (INPUT_RECORD *)data;
723
724     if (len != req->count * sizeof(INPUT_RECORD))
725         fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
726                               len, req->count );
727     reply.written = write_console_input( req->handle, req->count, records );
728     send_reply( current, -1, 1, &reply, sizeof(reply) );
729 }
730
731 /* fetch input records from a console input queue */
732 DECL_HANDLER(read_console_input)
733 {
734     read_console_input( req->handle, req->count, req->flush );
735 }
736
737 /* create a change notification */
738 DECL_HANDLER(create_change_notification)
739 {
740     struct object *obj;
741     struct create_change_notification_reply reply = { -1 };
742
743     if ((obj = create_change_notification( req->subtree, req->filter )))
744     {
745         reply.handle = alloc_handle( current->process, obj,
746                                      STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
747         release_object( obj );
748     }
749     send_reply( current, -1, 1, &reply, sizeof(reply) );
750 }
751
752 /* create a file mapping */
753 DECL_HANDLER(create_mapping)
754 {
755     struct object *obj;
756     struct create_mapping_reply reply = { -1 };
757     char *name = (char *)data;
758     if (!len) name = NULL;
759     else CHECK_STRING( "create_mapping", name, len );
760
761     if ((obj = create_mapping( req->size_high, req->size_low,
762                                req->protect, req->handle, name )))
763     {
764         int access = FILE_MAP_ALL_ACCESS;
765         if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE;
766         reply.handle = alloc_handle( current->process, obj, access, req->inherit );
767         release_object( obj );
768     }
769     send_reply( current, -1, 1, &reply, sizeof(reply) );
770 }
771
772 /* get a mapping information */
773 DECL_HANDLER(get_mapping_info)
774 {
775     struct get_mapping_info_reply reply;
776     int map_fd = get_mapping_info( req->handle, &reply );
777     send_reply( current, map_fd, 1, &reply, sizeof(reply) );
778 }
779
780 /* create a device */
781 DECL_HANDLER(create_device)
782 {
783     struct object *obj;
784     struct create_device_reply reply = { -1 };
785
786     if ((obj = create_device( req->id )))
787     {
788         reply.handle = alloc_handle( current->process, obj,
789                                      req->access, req->inherit );
790         release_object( obj );
791     }
792     send_reply( current, -1, 1, &reply, sizeof(reply) );
793 }
794
795 /* create a snapshot */
796 DECL_HANDLER(create_snapshot)
797 {
798     struct object *obj;
799     struct create_snapshot_reply reply = { -1 };
800
801     if ((obj = create_snapshot( req->flags )))
802     {
803         reply.handle = alloc_handle( current->process, obj, 0, req->inherit );
804         release_object( obj );
805     }
806     send_reply( current, -1, 1, &reply, sizeof(reply) );
807 }
808
809 /* get the next process from a snapshot */
810 DECL_HANDLER(next_process)
811 {
812     struct next_process_reply reply;
813     snapshot_next_process( req->handle, req->reset, &reply );
814     send_reply( current, -1, 1, &reply, sizeof(reply) );
815 }
816