quartz: Make it possible to just override IMediaSeeking::GetCurrentPosition.
[wine] / server / device.c
1 /*
2  * Server-side device support
3  *
4  * Copyright (C) 2007 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winternl.h"
30
31 #include "object.h"
32 #include "file.h"
33 #include "handle.h"
34 #include "request.h"
35
36 struct ioctl_call
37 {
38     struct object          obj;           /* object header */
39     struct list            dev_entry;     /* entry in device queue */
40     struct list            mgr_entry;     /* entry in manager queue */
41     struct device         *device;        /* device containing this ioctl */
42     struct thread         *thread;        /* thread that queued the ioctl */
43     client_ptr_t           user_arg;      /* user arg used to identify the request */
44     struct async          *async;         /* pending async op */
45     ioctl_code_t           code;          /* ioctl code */
46     unsigned int           status;        /* resulting status (or STATUS_PENDING) */
47     data_size_t            in_size;       /* size of input data */
48     void                  *in_data;       /* input data */
49     data_size_t            out_size;      /* size of output data */
50     void                  *out_data;      /* output data */
51 };
52
53 static void ioctl_call_dump( struct object *obj, int verbose );
54 static int ioctl_call_signaled( struct object *obj, struct thread *thread );
55 static void ioctl_call_destroy( struct object *obj );
56
57 static const struct object_ops ioctl_call_ops =
58 {
59     sizeof(struct ioctl_call),        /* size */
60     ioctl_call_dump,                  /* dump */
61     no_get_type,                      /* get_type */
62     add_queue,                        /* add_queue */
63     remove_queue,                     /* remove_queue */
64     ioctl_call_signaled,              /* signaled */
65     no_satisfied,                     /* satisfied */
66     no_signal,                        /* signal */
67     no_get_fd,                        /* get_fd */
68     no_map_access,                    /* map_access */
69     default_get_sd,                   /* get_sd */
70     default_set_sd,                   /* set_sd */
71     no_lookup_name,                   /* lookup_name */
72     no_open_file,                     /* open_file */
73     no_close_handle,                  /* close_handle */
74     ioctl_call_destroy                /* destroy */
75 };
76
77
78 struct device_manager
79 {
80     struct object          obj;           /* object header */
81     struct list            devices;       /* list of devices */
82     struct list            requests;      /* list of pending ioctls across all devices */
83 };
84
85 static void device_manager_dump( struct object *obj, int verbose );
86 static int device_manager_signaled( struct object *obj, struct thread *thread );
87 static void device_manager_destroy( struct object *obj );
88
89 static const struct object_ops device_manager_ops =
90 {
91     sizeof(struct device_manager),    /* size */
92     device_manager_dump,              /* dump */
93     no_get_type,                      /* get_type */
94     add_queue,                        /* add_queue */
95     remove_queue,                     /* remove_queue */
96     device_manager_signaled,          /* signaled */
97     no_satisfied,                     /* satisfied */
98     no_signal,                        /* signal */
99     no_get_fd,                        /* get_fd */
100     no_map_access,                    /* map_access */
101     default_get_sd,                   /* get_sd */
102     default_set_sd,                   /* set_sd */
103     no_lookup_name,                   /* lookup_name */
104     no_open_file,                     /* open_file */
105     no_close_handle,                  /* close_handle */
106     device_manager_destroy            /* destroy */
107 };
108
109
110 struct device
111 {
112     struct object          obj;           /* object header */
113     struct device_manager *manager;       /* manager for this device (or NULL if deleted) */
114     struct fd             *fd;            /* file descriptor for ioctl */
115     client_ptr_t           user_ptr;      /* opaque ptr for client side */
116     struct list            entry;         /* entry in device manager list */
117     struct list            requests;      /* list of pending ioctl requests */
118 };
119
120 static void device_dump( struct object *obj, int verbose );
121 static struct object_type *device_get_type( struct object *obj );
122 static struct fd *device_get_fd( struct object *obj );
123 static void device_destroy( struct object *obj );
124 static struct object *device_open_file( struct object *obj, unsigned int access,
125                                         unsigned int sharing, unsigned int options );
126 static enum server_fd_type device_get_fd_type( struct fd *fd );
127 static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
128                                   int blocking, const void *data, data_size_t size );
129
130 static const struct object_ops device_ops =
131 {
132     sizeof(struct device),            /* size */
133     device_dump,                      /* dump */
134     device_get_type,                  /* get_type */
135     no_add_queue,                     /* add_queue */
136     NULL,                             /* remove_queue */
137     NULL,                             /* signaled */
138     no_satisfied,                     /* satisfied */
139     no_signal,                        /* signal */
140     device_get_fd,                    /* get_fd */
141     default_fd_map_access,            /* map_access */
142     default_get_sd,                   /* get_sd */
143     default_set_sd,                   /* set_sd */
144     no_lookup_name,                   /* lookup_name */
145     device_open_file,                 /* open_file */
146     no_close_handle,                  /* close_handle */
147     device_destroy                    /* destroy */
148 };
149
150 static const struct fd_ops device_fd_ops =
151 {
152     default_fd_get_poll_events,       /* get_poll_events */
153     default_poll_event,               /* poll_event */
154     no_flush,                         /* flush */
155     device_get_fd_type,               /* get_fd_type */
156     device_ioctl,                     /* ioctl */
157     default_fd_queue_async,           /* queue_async */
158     default_fd_reselect_async,        /* reselect_async */
159     default_fd_cancel_async           /* cancel_async */
160 };
161
162
163 static void ioctl_call_dump( struct object *obj, int verbose )
164 {
165     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
166     fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->device );
167 }
168
169 static int ioctl_call_signaled( struct object *obj, struct thread *thread )
170 {
171     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
172
173     return !ioctl->device;  /* device is cleared once the ioctl has completed */
174 }
175
176 static void ioctl_call_destroy( struct object *obj )
177 {
178     struct ioctl_call *ioctl = (struct ioctl_call *)obj;
179
180     free( ioctl->in_data );
181     free( ioctl->out_data );
182     if (ioctl->async)
183     {
184         async_terminate( ioctl->async, STATUS_CANCELLED );
185         release_object( ioctl->async );
186     }
187     if (ioctl->device) release_object( ioctl->device );
188     release_object( ioctl->thread );
189 }
190
191 static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code,
192                                         const void *in_data, data_size_t in_size,
193                                         data_size_t out_size )
194 {
195     struct ioctl_call *ioctl;
196
197     if ((ioctl = alloc_object( &ioctl_call_ops )))
198     {
199         ioctl->device   = (struct device *)grab_object( device );
200         ioctl->code     = code;
201         ioctl->async    = NULL;
202         ioctl->status   = STATUS_PENDING;
203         ioctl->in_size  = in_size;
204         ioctl->in_data  = NULL;
205         ioctl->out_size = out_size;
206         ioctl->out_data = NULL;
207
208         if (ioctl->in_size && !(ioctl->in_data = memdup( in_data, in_size )))
209         {
210             release_object( ioctl );
211             ioctl = NULL;
212         }
213     }
214     return ioctl;
215 }
216
217 static void set_ioctl_result( struct ioctl_call *ioctl, unsigned int status,
218                               const void *out_data, data_size_t out_size )
219 {
220     struct device *device = ioctl->device;
221
222     if (!device) return;  /* already finished */
223
224     /* FIXME: handle the STATUS_PENDING case */
225     ioctl->status = status;
226     ioctl->out_size = min( ioctl->out_size, out_size );
227     if (ioctl->out_size && !(ioctl->out_data = memdup( out_data, ioctl->out_size )))
228         ioctl->out_size = 0;
229     release_object( device );
230     ioctl->device = NULL;
231     if (ioctl->async)
232     {
233         if (ioctl->out_size) status = STATUS_ALERTED;
234         async_terminate( ioctl->async, status );
235         release_object( ioctl->async );
236         ioctl->async = NULL;
237     }
238     wake_up( &ioctl->obj, 0 );
239
240     if (status != STATUS_ALERTED)
241     {
242         /* remove it from the device queue */
243         /* (for STATUS_ALERTED this will be done in get_ioctl_result) */
244         list_remove( &ioctl->dev_entry );
245         release_object( ioctl );  /* no longer on the device queue */
246     }
247 }
248
249
250 static void device_dump( struct object *obj, int verbose )
251 {
252     struct device *device = (struct device *)obj;
253
254     fprintf( stderr, "Device " );
255     dump_object_name( &device->obj );
256     fputc( '\n', stderr );
257 }
258
259 static struct object_type *device_get_type( struct object *obj )
260 {
261     static const WCHAR name[] = {'D','e','v','i','c','e'};
262     static const struct unicode_str str = { name, sizeof(name) };
263     return get_object_type( &str );
264 }
265
266 static struct fd *device_get_fd( struct object *obj )
267 {
268     struct device *device = (struct device *)obj;
269
270     return (struct fd *)grab_object( device->fd );
271 }
272
273 static void device_destroy( struct object *obj )
274 {
275     struct device *device = (struct device *)obj;
276     struct ioctl_call *ioctl, *next;
277
278     LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry )
279     {
280         list_remove( &ioctl->dev_entry );
281         release_object( ioctl );  /* no longer on the device queue */
282     }
283     if (device->fd) release_object( device->fd );
284     if (device->manager) list_remove( &device->entry );
285 }
286
287 static struct object *device_open_file( struct object *obj, unsigned int access,
288                                         unsigned int sharing, unsigned int options )
289 {
290     return grab_object( obj );
291 }
292
293 static enum server_fd_type device_get_fd_type( struct fd *fd )
294 {
295     return FD_TYPE_DEVICE;
296 }
297
298 static struct ioctl_call *find_ioctl_call( struct device *device, struct thread *thread,
299                                            client_ptr_t user_arg )
300 {
301     struct ioctl_call *ioctl;
302
303     LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct ioctl_call, dev_entry )
304         if (ioctl->thread == thread && ioctl->user_arg == user_arg) return ioctl;
305
306     set_error( STATUS_INVALID_PARAMETER );
307     return NULL;
308 }
309
310 static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
311                                   int blocking, const void *data, data_size_t size )
312 {
313     struct device *device = get_fd_user( fd );
314     struct ioctl_call *ioctl;
315     obj_handle_t handle;
316
317     if (!device->manager)  /* it has been deleted */
318     {
319         set_error( STATUS_FILE_DELETED );
320         return 0;
321     }
322
323     if (!(ioctl = create_ioctl( device, code, data, size, get_reply_max_size() )))
324         return 0;
325
326     ioctl->thread   = (struct thread *)grab_object( current );
327     ioctl->user_arg = async_data->arg;
328
329     if (!(handle = alloc_handle( current->process, ioctl, SYNCHRONIZE, 0 )))
330     {
331         release_object( ioctl );
332         return 0;
333     }
334
335     if (!(ioctl->async = fd_queue_async( device->fd, async_data, ASYNC_TYPE_WAIT )))
336     {
337         close_handle( current->process, handle );
338         release_object( ioctl );
339         return 0;
340     }
341     list_add_tail( &device->requests, &ioctl->dev_entry );
342     list_add_tail( &device->manager->requests, &ioctl->mgr_entry );
343     if (list_head( &device->manager->requests ) == &ioctl->mgr_entry)  /* first one */
344         wake_up( &device->manager->obj, 0 );
345     /* don't release ioctl since it is now queued in the device */
346     set_error( STATUS_PENDING );
347     return handle;
348 }
349
350 static struct device *create_device( struct directory *root, const struct unicode_str *name,
351                                      struct device_manager *manager, unsigned int attr )
352 {
353     struct device *device;
354
355     if ((device = create_named_object_dir( root, name, attr, &device_ops )))
356     {
357         if (get_error() != STATUS_OBJECT_NAME_EXISTS)
358         {
359             /* initialize it if it didn't already exist */
360             device->manager = manager;
361             list_add_tail( &manager->devices, &device->entry );
362             list_init( &device->requests );
363             if (!(device->fd = alloc_pseudo_fd( &device_fd_ops, &device->obj, 0 )))
364             {
365                 release_object( device );
366                 device = NULL;
367             }
368         }
369     }
370     return device;
371 }
372
373 static void delete_device( struct device *device )
374 {
375     struct ioctl_call *ioctl, *next;
376
377     if (!device->manager) return;  /* already deleted */
378
379     /* terminate all pending requests */
380     LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry )
381     {
382         list_remove( &ioctl->mgr_entry );
383         set_ioctl_result( ioctl, STATUS_FILE_DELETED, NULL, 0 );
384     }
385     unlink_named_object( &device->obj );
386     list_remove( &device->entry );
387     device->manager = NULL;
388 }
389
390
391 static void device_manager_dump( struct object *obj, int verbose )
392 {
393     fprintf( stderr, "Device manager\n" );
394 }
395
396 static int device_manager_signaled( struct object *obj, struct thread *thread )
397 {
398     struct device_manager *manager = (struct device_manager *)obj;
399
400     return !list_empty( &manager->requests );
401 }
402
403 static void device_manager_destroy( struct object *obj )
404 {
405     struct device_manager *manager = (struct device_manager *)obj;
406     struct list *ptr;
407
408     while ((ptr = list_head( &manager->devices )))
409     {
410         struct device *device = LIST_ENTRY( ptr, struct device, entry );
411         delete_device( device );
412     }
413 }
414
415 static struct device_manager *create_device_manager(void)
416 {
417     struct device_manager *manager;
418
419     if ((manager = alloc_object( &device_manager_ops )))
420     {
421         list_init( &manager->devices );
422         list_init( &manager->requests );
423     }
424     return manager;
425 }
426
427
428 /* create a device manager */
429 DECL_HANDLER(create_device_manager)
430 {
431     struct device_manager *manager = create_device_manager();
432
433     if (manager)
434     {
435         reply->handle = alloc_handle( current->process, manager, req->access, req->attributes );
436         release_object( manager );
437     }
438 }
439
440
441 /* create a device */
442 DECL_HANDLER(create_device)
443 {
444     struct device *device;
445     struct unicode_str name;
446     struct device_manager *manager;
447     struct directory *root = NULL;
448
449     if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
450                                                              0, &device_manager_ops )))
451         return;
452
453     get_req_unicode_str( &name );
454     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
455     {
456         release_object( manager );
457         return;
458     }
459
460     if ((device = create_device( root, &name, manager, req->attributes )))
461     {
462         device->user_ptr = req->user_ptr;
463         reply->handle = alloc_handle( current->process, device, req->access, req->attributes );
464         release_object( device );
465     }
466
467     if (root) release_object( root );
468     release_object( manager );
469 }
470
471
472 /* delete a device */
473 DECL_HANDLER(delete_device)
474 {
475     struct device *device;
476
477     if ((device = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops )))
478     {
479         delete_device( device );
480         release_object( device );
481     }
482 }
483
484
485 /* retrieve the next pending device ioctl request */
486 DECL_HANDLER(get_next_device_request)
487 {
488     struct ioctl_call *ioctl;
489     struct device_manager *manager;
490     struct list *ptr;
491
492     if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
493                                                              0, &device_manager_ops )))
494         return;
495
496     if (req->prev)
497     {
498         if ((ioctl = (struct ioctl_call *)get_handle_obj( current->process, req->prev,
499                                                           0, &ioctl_call_ops )))
500         {
501             set_ioctl_result( ioctl, req->status, get_req_data(), get_req_data_size() );
502             close_handle( current->process, req->prev );  /* avoid an extra round-trip for close */
503             release_object( ioctl );
504         }
505         clear_error();
506     }
507
508     if ((ptr = list_head( &manager->requests )))
509     {
510         ioctl = LIST_ENTRY( ptr, struct ioctl_call, mgr_entry );
511         reply->code = ioctl->code;
512         reply->user_ptr = ioctl->device->user_ptr;
513         reply->in_size = ioctl->in_size;
514         reply->out_size = ioctl->out_size;
515         if (ioctl->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW );
516         else if ((reply->next = alloc_handle( current->process, ioctl, 0, 0 )))
517         {
518             set_reply_data_ptr( ioctl->in_data, ioctl->in_size );
519             ioctl->in_data = NULL;
520             ioctl->in_size = 0;
521             list_remove( &ioctl->mgr_entry );
522             list_init( &ioctl->mgr_entry );
523         }
524     }
525     else set_error( STATUS_PENDING );
526
527     release_object( manager );
528 }
529
530
531 /* retrieve results of an async ioctl */
532 DECL_HANDLER(get_ioctl_result)
533 {
534     struct device *device;
535     struct ioctl_call *ioctl;
536
537     if (!(device = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops )))
538         return;
539
540     if ((ioctl = find_ioctl_call( device, current, req->user_arg )))
541     {
542         if (ioctl->out_data)
543         {
544             data_size_t size = min( ioctl->out_size, get_reply_max_size() );
545             if (size)
546             {
547                 set_reply_data_ptr( ioctl->out_data, size );
548                 ioctl->out_data = NULL;
549             }
550         }
551         set_error( ioctl->status );
552         list_remove( &ioctl->dev_entry );
553         release_object( ioctl );  /* no longer on the device queue */
554     }
555     release_object( device );
556 }