kernel32: GlobalMemoryStatusEx: always report at least 1 byte of virtual memory even...
[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_close_handle,              /* close_handle */
67     symlink_destroy               /* destroy */
68 };
69
70 static void symlink_dump( struct object *obj, int verbose )
71 {
72     struct symlink *symlink = (struct symlink *)obj;
73     assert( obj->ops == &symlink_ops );
74
75     fprintf( stderr, "Symlink " );
76     dump_object_name( obj );
77     fprintf( stderr, " -> L\"" );
78     dump_strW( symlink->target, symlink->len / sizeof(WCHAR), stderr, "\"\"" );
79     fprintf( stderr, "\"\n" );
80 }
81
82 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
83                                            unsigned int attr )
84 {
85     struct symlink *symlink = (struct symlink *)obj;
86     struct unicode_str target_str, name_left;
87     struct object *target;
88
89     assert( obj->ops == &symlink_ops );
90     if (attr & OBJ_OPENLINK) return NULL;
91
92     target_str.str = symlink->target;
93     target_str.len = symlink->len;
94     if ((target = find_object_dir( NULL, &target_str, attr, &name_left )))
95     {
96         if (name_left.len)
97         {
98             release_object( target );
99             target = NULL;
100             set_error( STATUS_OBJECT_PATH_NOT_FOUND );
101         }
102     }
103     return target;
104 }
105
106 static unsigned int symlink_map_access( struct object *obj, unsigned int access )
107 {
108     if (access & GENERIC_READ)    access |= STANDARD_RIGHTS_READ | SYMBOLIC_LINK_QUERY;
109     if (access & GENERIC_WRITE)   access |= STANDARD_RIGHTS_WRITE;
110     if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE;
111     if (access & GENERIC_ALL)     access |= SYMBOLIC_LINK_ALL_ACCESS;
112     return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
113 }
114
115 static void symlink_destroy( struct object *obj )
116 {
117     struct symlink *symlink = (struct symlink *)obj;
118     assert( obj->ops == &symlink_ops );
119     free( symlink->target );
120 }
121
122 struct symlink *create_symlink( struct directory *root, const struct unicode_str *name,
123                                 unsigned int attr, const struct unicode_str *target )
124 {
125     struct symlink *symlink;
126
127     if (!target->len)
128     {
129         set_error( STATUS_INVALID_PARAMETER );
130         return NULL;
131     }
132     if ((symlink = create_named_object_dir( root, name, attr, &symlink_ops )) &&
133         (get_error() != STATUS_OBJECT_NAME_EXISTS))
134     {
135         if ((symlink->target = memdup( target->str, target->len )))
136             symlink->len = target->len;
137         else
138         {
139             release_object( symlink );
140             symlink = NULL;
141         }
142     }
143     return symlink;
144 }
145
146
147 /* create a symbolic link object */
148 DECL_HANDLER(create_symlink)
149 {
150     struct symlink *symlink;
151     struct unicode_str name, target;
152     struct directory *root = NULL;
153
154     if (req->name_len > get_req_data_size())
155     {
156         set_error( STATUS_INVALID_PARAMETER );
157         return;
158     }
159     name.str   = get_req_data();
160     target.str = name.str + req->name_len / sizeof(WCHAR);
161     name.len   = (target.str - name.str) * sizeof(WCHAR);
162     target.len = ((get_req_data_size() - name.len) / sizeof(WCHAR)) * sizeof(WCHAR);
163
164     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
165         return;
166
167     if ((symlink = create_symlink( root, &name, req->attributes, &target )))
168     {
169         reply->handle = alloc_handle( current->process, symlink, req->access, req->attributes );
170         release_object( symlink );
171     }
172
173     if (root) release_object( root );
174 }
175
176 /* open a symbolic link object */
177 DECL_HANDLER(open_symlink)
178 {
179     struct unicode_str name;
180     struct directory *root = NULL;
181     struct symlink *symlink;
182
183     get_req_unicode_str( &name );
184     if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
185         return;
186
187     if ((symlink = open_object_dir( root, &name, req->attributes | OBJ_OPENLINK, &symlink_ops )))
188     {
189         reply->handle = alloc_handle( current->process, &symlink->obj, req->access, req->attributes );
190         release_object( symlink );
191     }
192
193     if (root) release_object( root );
194 }
195
196 /* query a symbolic link object */
197 DECL_HANDLER(query_symlink)
198 {
199     struct symlink *symlink;
200
201     symlink = (struct symlink *)get_handle_obj( current->process, req->handle,
202                                                 SYMBOLIC_LINK_QUERY, &symlink_ops );
203     if (!symlink) return;
204
205     if (get_reply_max_size() < symlink->len)
206         set_error( STATUS_BUFFER_TOO_SMALL );
207     else
208         set_reply_data( symlink->target, symlink->len );
209     release_object( symlink );
210 }