server: Add an open_file() function to the object operations.
[wine] / server / symlink.c
1 /*
2  * Server-side symbolic link 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 "object.h"
39 #include "unicode.h"
40
41 struct symlink
42 {
43     struct object    obj;       /* object header */
44     WCHAR           *target;    /* target of the symlink */
45     data_size_t      len;       /* target len in bytes */
46 };
47
48 static void symlink_dump( struct object *obj, int verbose );
49 static unsigned int symlink_map_access( struct object *obj, unsigned int access );
50 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
51                                            unsigned int attr );
52 static void symlink_destroy( struct object *obj );
53
54 static const struct object_ops symlink_ops =
55 {
56     sizeof(struct symlink),       /* size */
57     symlink_dump,                 /* dump */
58     no_add_queue,                 /* add_queue */
59     NULL,                         /* remove_queue */
60     NULL,                         /* signaled */
61     NULL,                         /* satisfied */
62     no_signal,                    /* signal */
63     no_get_fd,                    /* get_fd */
64     symlink_map_access,           /* map_access */
65     symlink_lookup_name,          /* lookup_name */
66     no_open_file,                 /* open_file */
67     no_close_handle,              /* close_handle */
68     symlink_destroy               /* destroy */
69 };
70
71 static void symlink_dump( struct object *obj, int verbose )
72 {
73     struct symlink *symlink = (struct symlink *)obj;
74     assert( obj->ops == &symlink_ops );
75
76     fprintf( stderr, "Symlink " );
77     dump_object_name( obj );
78     fprintf( stderr, " -> L\"" );
79     dump_strW( symlink->target, symlink->len / sizeof(WCHAR), stderr, "\"\"" );
80     fprintf( stderr, "\"\n" );
81 }
82
83 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
84                                            unsigned int attr )
85 {
86     struct symlink *symlink = (struct symlink *)obj;
87     struct unicode_str target_str, name_left;
88     struct object *target;
89
90     assert( obj->ops == &symlink_ops );
91     if (attr & OBJ_OPENLINK) return NULL;
92
93     target_str.str = symlink->target;
94     target_str.len = symlink->len;
95     if ((target = find_object_dir( NULL, &target_str, attr, &name_left )))
96     {
97         if (name_left.len)
98         {
99             release_object( target );
100             target = NULL;
101             set_error( STATUS_OBJECT_PATH_NOT_FOUND );
102         }
103     }
104     return target;
105 }
106
107 static unsigned int symlink_map_access( struct object *obj, unsigned int access )
108 {
109     if (access & GENERIC_READ)    access |= STANDARD_RIGHTS_READ | SYMBOLIC_LINK_QUERY;
110     if (access & GENERIC_WRITE)   access |= STANDARD_RIGHTS_WRITE;
111     if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE;
112     if (access & GENERIC_ALL)     access |= SYMBOLIC_LINK_ALL_ACCESS;
113     return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
114 }
115
116 static void symlink_destroy( struct object *obj )
117 {
118     struct symlink *symlink = (struct symlink *)obj;
119     assert( obj->ops == &symlink_ops );
120     free( symlink->target );
121 }
122
123 struct symlink *create_symlink( struct directory *root, const struct unicode_str *name,
124                                 unsigned int attr, const struct unicode_str *target )
125 {
126     struct symlink *symlink;
127
128     if (!target->len)
129     {
130         set_error( STATUS_INVALID_PARAMETER );
131         return NULL;
132     }
133     if ((symlink = create_named_object_dir( root, name, attr, &symlink_ops )) &&
134         (get_error() != STATUS_OBJECT_NAME_EXISTS))
135     {
136         if ((symlink->target = memdup( target->str, target->len )))
137             symlink->len = target->len;
138         else
139         {
140             release_object( symlink );
141             symlink = NULL;
142         }
143     }
144     return symlink;
145 }
146
147
148 /* create a symbolic link object */
149 DECL_HANDLER(create_symlink)
150 {
151     struct symlink *symlink;
152     struct unicode_str name, target;
153     struct directory *root = NULL;
154
155     if (req->name_len > get_req_data_size())
156     {
157         set_error( STATUS_INVALID_PARAMETER );
158         return;
159     }
160     name.str   = get_req_data();
161     target.str = name.str + req->name_len / sizeof(WCHAR);
162     name.len   = (target.str - name.str) * sizeof(WCHAR);
163     target.len = ((get_req_data_size() - name.len) / sizeof(WCHAR)) * sizeof(WCHAR);
164
165     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
166         return;
167
168     if ((symlink = create_symlink( root, &name, req->attributes, &target )))
169     {
170         reply->handle = alloc_handle( current->process, symlink, req->access, req->attributes );
171         release_object( symlink );
172     }
173
174     if (root) release_object( root );
175 }
176
177 /* open a symbolic link object */
178 DECL_HANDLER(open_symlink)
179 {
180     struct unicode_str name;
181     struct directory *root = NULL;
182     struct symlink *symlink;
183
184     get_req_unicode_str( &name );
185     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
186         return;
187
188     if ((symlink = open_object_dir( root, &name, req->attributes | OBJ_OPENLINK, &symlink_ops )))
189     {
190         reply->handle = alloc_handle( current->process, &symlink->obj, req->access, req->attributes );
191         release_object( symlink );
192     }
193
194     if (root) release_object( root );
195 }
196
197 /* query a symbolic link object */
198 DECL_HANDLER(query_symlink)
199 {
200     struct symlink *symlink;
201
202     symlink = (struct symlink *)get_handle_obj( current->process, req->handle,
203                                                 SYMBOLIC_LINK_QUERY, &symlink_ops );
204     if (!symlink) return;
205
206     if (get_reply_max_size() < symlink->len)
207         set_error( STATUS_BUFFER_TOO_SMALL );
208     else
209         set_reply_data( symlink->target, symlink->len );
210     release_object( symlink );
211 }