server: Add an open_file() function to the object operations.
[wine] / server / directory.c
1 /*
2  * Server-side directory object management
3  *
4  * Copyright (C) 2005 Vitaliy Margolen
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
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "winternl.h"
34 #include "ddk/wdm.h"
35
36 #include "handle.h"
37 #include "request.h"
38 #include "process.h"
39 #include "object.h"
40 #include "unicode.h"
41
42 #define HASH_SIZE 7  /* default hash size */
43
44 struct directory
45 {
46     struct object     obj;        /* object header */
47     struct namespace *entries;    /* directory's name space */
48 };
49
50 static void directory_dump( struct object *obj, int verbose );
51 static unsigned int directory_map_access( struct object *obj, unsigned int access );
52 static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
53                                              unsigned int attr );
54 static void directory_destroy( struct object *obj );
55
56 static const struct object_ops directory_ops =
57 {
58     sizeof(struct directory),     /* size */
59     directory_dump,               /* dump */
60     no_add_queue,                 /* add_queue */
61     NULL,                         /* remove_queue */
62     NULL,                         /* signaled */
63     NULL,                         /* satisfied */
64     no_signal,                    /* signal */
65     no_get_fd,                    /* get_fd */
66     directory_map_access,         /* map_access */
67     directory_lookup_name,        /* lookup_name */
68     no_open_file,                 /* open_file */
69     no_close_handle,              /* close_handle */
70     directory_destroy             /* destroy */
71 };
72
73 static struct directory *root_directory;
74
75
76 static void directory_dump( struct object *obj, int verbose )
77 {
78     assert( obj->ops == &directory_ops );
79
80     fputs( "Directory ", stderr );
81     dump_object_name( obj );
82     fputc( '\n', stderr );
83 }
84
85 static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
86                                              unsigned int attr )
87 {
88     struct directory *dir = (struct directory *)obj;
89     struct object *found;
90     struct unicode_str tmp;
91     const WCHAR *p;
92
93     assert( obj->ops == &directory_ops );
94
95     if (!(p = memchrW( name->str, '\\', name->len / sizeof(WCHAR) )))
96         /* Last element in the path name */
97         tmp.len = name->len;
98     else
99         tmp.len = (p - name->str) * sizeof(WCHAR);
100
101     tmp.str = name->str;
102     if ((found = find_object( dir->entries, &tmp, attr )))
103     {
104         /* Skip trailing \\ */
105         if (p)
106         {
107             p++;
108             tmp.len += sizeof(WCHAR);
109         }
110         /* Move to the next element*/
111         name->str = p;
112         name->len -= tmp.len;
113         return found;
114     }
115
116     if (name->str)
117     {
118         if (tmp.len == 0) /* Double backslash */
119             set_error( STATUS_OBJECT_NAME_INVALID );
120         else if (p)  /* Path still has backslashes */
121             set_error( STATUS_OBJECT_PATH_NOT_FOUND );
122     }
123     return NULL;
124 }
125
126 static unsigned int directory_map_access( struct object *obj, unsigned int access )
127 {
128     if (access & GENERIC_READ)    access |= FILE_GENERIC_READ;
129     if (access & GENERIC_WRITE)   access |= FILE_GENERIC_WRITE;
130     if (access & GENERIC_EXECUTE) access |= FILE_GENERIC_EXECUTE;
131     if (access & GENERIC_ALL)     access |= FILE_ALL_ACCESS;
132     return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
133 }
134
135 static void directory_destroy( struct object *obj )
136 {
137     struct directory *dir = (struct directory *)obj;
138     assert( obj->ops == &directory_ops );
139     free( dir->entries );
140 }
141
142 static struct directory *create_directory( struct directory *root, const struct unicode_str *name,
143                                            unsigned int attr, unsigned int hash_size )
144 {
145     struct directory *dir;
146
147     if ((dir = create_named_object_dir( root, name, attr, &directory_ops )) &&
148         get_error() != STATUS_OBJECT_NAME_EXISTS)
149     {
150         if (!(dir->entries = create_namespace( hash_size )))
151         {
152             release_object( dir );
153             dir = NULL;
154         }
155     }
156     return dir;
157 }
158
159 struct directory *get_directory_obj( struct process *process, obj_handle_t handle, unsigned int access )
160 {
161     return (struct directory *)get_handle_obj( process, handle, access, &directory_ops );
162 }
163
164 /******************************************************************************
165  * Find an object by its name in a given root object
166  *
167  * PARAMS
168  *  root      [I] directory to start search from or NULL to start from \\
169  *  name      [I] object name to search for
170  *  attr      [I] OBJECT_ATTRIBUTES.Attributes
171  *  name_left [O] [optional] leftover name if object is not found
172  *
173  * RETURNS
174  *  NULL:      If params are invalid
175  *  Found:     If object with exact name is found returns that object
176  *             (name_left->len == 0). Object's refcount is incremented
177  *  Not found: The last matched parent. (name_left->len > 0)
178  *             Parent's refcount is incremented.
179  */
180 struct object *find_object_dir( struct directory *root, const struct unicode_str *name,
181                                 unsigned int attr, struct unicode_str *name_left )
182 {
183     struct object *obj, *parent;
184     struct unicode_str name_tmp;
185
186     if (name) name_tmp = *name;
187     else name_tmp.len = 0;
188
189     /* Arguments check:
190      * - Either rootdir or name have to be specified
191      * - If root is specified path shouldn't start with backslash */
192     if (root)
193     {
194         if (name_tmp.len && name_tmp.str[0] == '\\')
195         {
196             set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
197             return NULL;
198         }
199         parent = grab_object( root );
200     }
201     else
202     {
203         if (!name_tmp.len || name_tmp.str[0] != '\\')
204         {
205             set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
206             return NULL;
207         }
208         parent = grab_object( &root_directory->obj );
209         /* skip leading backslash */
210         name_tmp.str++;
211         name_tmp.len -= sizeof(WCHAR);
212     }
213
214     /* Special case for opening RootDirectory */
215     if (!name_tmp.len) goto done;
216
217     while ((obj = parent->ops->lookup_name( parent, &name_tmp, attr )))
218     {
219         /* move to the next element */
220         release_object ( parent );
221         parent = obj;
222     }
223     if (get_error())
224     {
225         release_object( parent );
226         return NULL;
227     }
228
229     done:
230     if (name_left) *name_left = name_tmp;
231     return parent;
232 }
233
234 /* create a named (if name is present) or unnamed object. */
235 void *create_named_object_dir( struct directory *root, const struct unicode_str *name,
236                                unsigned int attributes, const struct object_ops *ops )
237 {
238     struct object *obj, *new_obj = NULL;
239     struct unicode_str new_name;
240
241     if (!name || !name->len) return alloc_object( ops );
242
243     if (!(obj = find_object_dir( root, name, attributes, &new_name ))) return NULL;
244     if (!new_name.len)
245     {
246         if (attributes & OBJ_OPENIF && obj->ops == ops)
247             set_error( STATUS_OBJECT_NAME_EXISTS );
248         else
249         {
250             release_object( obj );
251             obj = NULL;
252             if (attributes & OBJ_OPENIF)
253                 set_error( STATUS_OBJECT_TYPE_MISMATCH );
254             else
255                 set_error( STATUS_OBJECT_NAME_COLLISION );
256         }
257         return obj;
258     }
259
260     /* ATM we can't insert objects into anything else but directories */
261     if (obj->ops != &directory_ops)
262         set_error( STATUS_OBJECT_TYPE_MISMATCH );
263     else
264     {
265         struct directory *dir = (struct directory *)obj;
266         if ((new_obj = create_object( dir->entries, ops, &new_name, &dir->obj )))
267             clear_error();
268     }
269
270     release_object( obj );
271     return new_obj;
272 }
273
274 /* open a new handle to an existing object */
275 void *open_object_dir( struct directory *root, const struct unicode_str *name,
276                        unsigned int attr, const struct object_ops *ops )
277 {
278     struct unicode_str name_left;
279     struct object *obj;
280
281     if ((obj = find_object_dir( root, name, attr, &name_left )))
282     {
283         if (name_left.len) /* not fully parsed */
284             set_error( STATUS_OBJECT_NAME_NOT_FOUND );
285         else if (ops && obj->ops != ops)
286             set_error( STATUS_OBJECT_TYPE_MISMATCH );
287         else
288             return obj;
289
290         release_object( obj );
291     }
292     return NULL;
293 }
294
295
296 /* Global initialization */
297
298 void init_directories(void)
299 {
300     /* Directories */
301     static const WCHAR dir_globalW[] = {'\\','?','?'};
302     static const WCHAR dir_driverW[] = {'D','r','i','v','e','r'};
303     static const WCHAR dir_deviceW[] = {'D','e','v','i','c','e'};
304     static const WCHAR dir_basenamedW[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'};
305     static const struct unicode_str dir_global_str = {dir_globalW, sizeof(dir_globalW)};
306     static const struct unicode_str dir_driver_str = {dir_driverW, sizeof(dir_driverW)};
307     static const struct unicode_str dir_device_str = {dir_deviceW, sizeof(dir_deviceW)};
308     static const struct unicode_str dir_basenamed_str = {dir_basenamedW, sizeof(dir_basenamedW)};
309
310     /* symlinks */
311     static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'};
312     static const WCHAR link_globalW[] = {'G','l','o','b','a','l'};
313     static const WCHAR link_localW[]  = {'L','o','c','a','l'};
314     static const struct unicode_str link_dosdev_str = {link_dosdevW, sizeof(link_dosdevW)};
315     static const struct unicode_str link_global_str = {link_globalW, sizeof(link_globalW)};
316     static const struct unicode_str link_local_str  = {link_localW, sizeof(link_localW)};
317
318     /* devices */
319     static const WCHAR pipeW[] = {'P','I','P','E'};
320     static const WCHAR mailslotW[] = {'M','A','I','L','S','L','O','T'};
321     static const struct unicode_str pipe_str = {pipeW, sizeof(pipeW)};
322     static const struct unicode_str mailslot_str = {mailslotW, sizeof(mailslotW)};
323
324     struct directory *dir_driver, *dir_device, *dir_global, *dir_basenamed;
325     struct symlink *link_dosdev, *link_global1, *link_global2, *link_local;
326
327     root_directory = create_directory( NULL, NULL, 0, HASH_SIZE );
328     dir_driver     = create_directory( root_directory, &dir_driver_str, 0, HASH_SIZE );
329     dir_device     = create_directory( root_directory, &dir_device_str, 0, HASH_SIZE );
330     make_object_static( &root_directory->obj );
331     make_object_static( &dir_driver->obj );
332     make_object_static( &dir_device->obj );
333
334     dir_global     = create_directory( NULL, &dir_global_str, 0, HASH_SIZE );
335     /* use a larger hash table for this one since it can contain a lot of objects */
336     dir_basenamed  = create_directory( NULL, &dir_basenamed_str, 0, 37 );
337
338     /* symlinks */
339     link_dosdev    = create_symlink( root_directory, &link_dosdev_str, 0, &dir_global_str );
340     link_global1   = create_symlink( dir_global, &link_global_str, 0, &dir_global_str );
341     link_global2   = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str );
342     link_local     = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str );
343     make_object_static( (struct object *)link_dosdev );
344     make_object_static( (struct object *)link_global1 );
345     make_object_static( (struct object *)link_global2 );
346     make_object_static( (struct object *)link_local );
347
348     /* devices */
349     create_named_pipe_device( dir_global, &pipe_str );
350     create_mailslot_device( dir_global, &mailslot_str );
351
352     /* the symlinks or devices hold references so we can release these */
353     release_object( dir_global );
354     release_object( dir_basenamed );
355 }
356
357 /* create a directory object */
358 DECL_HANDLER(create_directory)
359 {
360     struct unicode_str name;
361     struct directory *dir, *root = NULL;
362
363     reply->handle = 0;
364     get_req_unicode_str( &name );
365     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
366         return;
367
368     if ((dir = create_directory( root, &name, req->attributes, HASH_SIZE )))
369     {
370         reply->handle = alloc_handle( current->process, dir, req->access, req->attributes );
371         release_object( dir );
372     }
373
374     if (root) release_object( root );
375 }
376
377 /* open a directory object */
378 DECL_HANDLER(open_directory)
379 {
380     struct unicode_str name;
381     struct directory *dir, *root = NULL;
382
383     get_req_unicode_str( &name );
384     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
385         return;
386
387     if ((dir = open_object_dir( root, &name, req->attributes, &directory_ops )))
388     {
389         reply->handle = alloc_handle( current->process, &dir->obj, req->access, req->attributes );
390         release_object( dir );
391     }
392
393     if (root) release_object( root );
394 }