progman: Added Hebrew translation.
[wine] / dlls / ntdll / om.c
1 /*
2  *      Object management functions
3  *
4  * Copyright 1999, 2000 Juergen Schmied
5  * Copyright 2005 Vitaliy Margolen
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_IO_H
28 # include <io.h>
29 #endif
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "wine/debug.h"
37 #include "windef.h"
38 #include "winternl.h"
39 #include "ntdll_misc.h"
40 #include "wine/server.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
43
44
45 /*
46  *      Generic object functions
47  */
48
49 /******************************************************************************
50  * NtQueryObject [NTDLL.@]
51  * ZwQueryObject [NTDLL.@]
52  */
53 NTSTATUS WINAPI NtQueryObject(IN HANDLE handle,
54                               IN OBJECT_INFORMATION_CLASS info_class,
55                               OUT PVOID ptr, IN ULONG len, OUT PULONG used_len)
56 {
57     NTSTATUS status;
58
59     TRACE("(%p,0x%08x,%p,0x%08x,%p): stub\n",
60           handle, info_class, ptr, len, used_len);
61
62     if (used_len) *used_len = 0;
63
64     switch (info_class)
65     {
66     case ObjectBasicInformation:
67         {
68             POBJECT_BASIC_INFORMATION p = ptr;
69
70             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
71
72             SERVER_START_REQ( get_object_info )
73             {
74                 req->handle = wine_server_obj_handle( handle );
75                 status = wine_server_call( req );
76                 if (status == STATUS_SUCCESS)
77                 {
78                     memset( p, 0, sizeof(*p) );
79                     p->GrantedAccess = reply->access;
80                     p->PointerCount = reply->ref_count;
81                     p->HandleCount = 1; /* at least one */
82                     if (used_len) *used_len = sizeof(*p);
83                 }
84             }
85             SERVER_END_REQ;
86         }
87         break;
88     case ObjectNameInformation:
89         {
90             OBJECT_NAME_INFORMATION* p = ptr;
91             ANSI_STRING unix_name;
92
93             /* first try as a file object */
94
95             if (!(status = server_get_unix_name( handle, &unix_name )))
96             {
97                 UNICODE_STRING nt_name;
98
99                 if (!(status = wine_unix_to_nt_file_name( &unix_name, &nt_name )))
100                 {
101                     if (len < sizeof(*p))
102                         status = STATUS_INFO_LENGTH_MISMATCH;
103                     else if (len < sizeof(*p) + nt_name.MaximumLength)
104                         status = STATUS_BUFFER_OVERFLOW;
105                     else
106                     {
107                         p->Name.Buffer = (WCHAR *)(p + 1);
108                         p->Name.Length = nt_name.Length;
109                         p->Name.MaximumLength = nt_name.MaximumLength;
110                         memcpy( p->Name.Buffer, nt_name.Buffer, nt_name.MaximumLength );
111                     }
112                     if (used_len) *used_len = sizeof(*p) + nt_name.MaximumLength;
113                     RtlFreeUnicodeString( &nt_name );
114                 }
115                 RtlFreeAnsiString( &unix_name );
116                 break;
117             }
118             else if (status != STATUS_OBJECT_TYPE_MISMATCH) break;
119
120             /* not a file, treat as a generic object */
121
122             SERVER_START_REQ( get_object_info )
123             {
124                 req->handle = wine_server_obj_handle( handle );
125                 if (len > sizeof(*p)) wine_server_set_reply( req, p + 1, len - sizeof(*p) );
126                 status = wine_server_call( req );
127                 if (status == STATUS_SUCCESS)
128                 {
129                     if (!reply->total)  /* no name */
130                     {
131                         if (sizeof(*p) > len) status = STATUS_INFO_LENGTH_MISMATCH;
132                         else memset( p, 0, sizeof(*p) );
133                         if (used_len) *used_len = sizeof(*p);
134                     }
135                     else if (sizeof(*p) + reply->total + sizeof(WCHAR) > len)
136                     {
137                         if (used_len) *used_len = sizeof(*p) + reply->total + sizeof(WCHAR);
138                         status = STATUS_INFO_LENGTH_MISMATCH;
139                     }
140                     else
141                     {
142                         ULONG res = wine_server_reply_size( reply );
143                         p->Name.Buffer = (WCHAR *)(p + 1);
144                         p->Name.Length = res;
145                         p->Name.MaximumLength = res + sizeof(WCHAR);
146                         p->Name.Buffer[res / sizeof(WCHAR)] = 0;
147                         if (used_len) *used_len = sizeof(*p) + p->Name.MaximumLength;
148                     }
149                 }
150             }
151             SERVER_END_REQ;
152         }
153         break;
154     case ObjectDataInformation:
155         {
156             OBJECT_DATA_INFORMATION* p = ptr;
157
158             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
159
160             SERVER_START_REQ( set_handle_info )
161             {
162                 req->handle = wine_server_obj_handle( handle );
163                 req->flags  = 0;
164                 req->mask   = 0;
165                 status = wine_server_call( req );
166                 if (status == STATUS_SUCCESS)
167                 {
168                     p->InheritHandle = (reply->old_flags & HANDLE_FLAG_INHERIT) ? TRUE : FALSE;
169                     p->ProtectFromClose = (reply->old_flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ? TRUE : FALSE;
170                     if (used_len) *used_len = sizeof(*p);
171                 }
172             }
173             SERVER_END_REQ;
174         }
175         break;
176     default:
177         FIXME("Unsupported information class %u\n", info_class);
178         status = STATUS_NOT_IMPLEMENTED;
179         break;
180     }
181     return status;
182 }
183
184 /******************************************************************
185  *              NtSetInformationObject [NTDLL.@]
186  *              ZwSetInformationObject [NTDLL.@]
187  *
188  */
189 NTSTATUS WINAPI NtSetInformationObject(IN HANDLE handle,
190                                        IN OBJECT_INFORMATION_CLASS info_class,
191                                        IN PVOID ptr, IN ULONG len)
192 {
193     NTSTATUS status;
194
195     TRACE("(%p,0x%08x,%p,0x%08x): stub\n",
196           handle, info_class, ptr, len);
197
198     switch (info_class)
199     {
200     case ObjectDataInformation:
201         {
202             OBJECT_DATA_INFORMATION* p = ptr;
203
204             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
205
206             SERVER_START_REQ( set_handle_info )
207             {
208                 req->handle = wine_server_obj_handle( handle );
209                 req->flags  = 0;
210                 req->mask   = HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE;
211                 if (p->InheritHandle)    req->flags |= HANDLE_FLAG_INHERIT;
212                 if (p->ProtectFromClose) req->flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
213                 status = wine_server_call( req );
214             }
215             SERVER_END_REQ;
216         }
217         break;
218     default:
219         FIXME("Unsupported information class %u\n", info_class);
220         status = STATUS_NOT_IMPLEMENTED;
221         break;
222     }
223     return status;
224 }
225
226 /******************************************************************************
227  *  NtQuerySecurityObject       [NTDLL.@]
228  *
229  * An ntdll analogue to GetKernelObjectSecurity().
230  *
231  */
232 NTSTATUS WINAPI
233 NtQuerySecurityObject(
234         IN HANDLE Object,
235         IN SECURITY_INFORMATION RequestedInformation,
236         OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
237         IN ULONG Length,
238         OUT PULONG ResultLength)
239 {
240     PISECURITY_DESCRIPTOR_RELATIVE psd = pSecurityDescriptor;
241     NTSTATUS status;
242     unsigned int buffer_size = 512;
243     BOOLEAN need_more_memory;
244
245     TRACE("(%p,0x%08x,%p,0x%08x,%p)\n",
246         Object, RequestedInformation, pSecurityDescriptor, Length, ResultLength);
247
248     do
249     {
250         char *buffer = RtlAllocateHeap(GetProcessHeap(), 0, buffer_size);
251         if (!buffer)
252             return STATUS_NO_MEMORY;
253
254         need_more_memory = FALSE;
255
256         SERVER_START_REQ( get_security_object )
257         {
258             req->handle = wine_server_obj_handle( Object );
259             req->security_info = RequestedInformation;
260             wine_server_set_reply( req, buffer, buffer_size );
261             status = wine_server_call( req );
262             if (status == STATUS_SUCCESS)
263             {
264                 struct security_descriptor *sd = (struct security_descriptor *)buffer;
265                 if (reply->sd_len)
266                 {
267                     *ResultLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
268                         sd->owner_len + sd->group_len + sd->sacl_len + sd->dacl_len;
269                     if (Length >= *ResultLength)
270                     {
271                         psd->Revision = SECURITY_DESCRIPTOR_REVISION;
272                         psd->Sbz1 = 0;
273                         psd->Control = sd->control | SE_SELF_RELATIVE;
274                         psd->Owner = sd->owner_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) : 0;
275                         psd->Group = sd->group_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sd->owner_len : 0;
276                         psd->Sacl = sd->sacl_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sd->owner_len + sd->group_len : 0;
277                         psd->Dacl = sd->dacl_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sd->owner_len + sd->group_len + sd->sacl_len : 0;
278                         /* owner, group, sacl and dacl are the same type as in the server
279                          * and in the same order so we copy the memory in one block */
280                         memcpy((char *)pSecurityDescriptor + sizeof(SECURITY_DESCRIPTOR_RELATIVE),
281                                buffer + sizeof(struct security_descriptor),
282                                sd->owner_len + sd->group_len + sd->sacl_len + sd->dacl_len);
283                     }
284                     else
285                         status = STATUS_BUFFER_TOO_SMALL;
286                 }
287                 else
288                 {
289                     *ResultLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
290                     if (Length >= *ResultLength)
291                     {
292                         memset(psd, 0, sizeof(*psd));
293                         psd->Revision = SECURITY_DESCRIPTOR_REVISION;
294                         psd->Control = SE_SELF_RELATIVE;
295                     }
296                     else
297                         status = STATUS_BUFFER_TOO_SMALL;
298                 }
299             }
300             else if (status == STATUS_BUFFER_TOO_SMALL)
301             {
302                 buffer_size = reply->sd_len;
303                 need_more_memory = TRUE;
304             }
305         }
306         SERVER_END_REQ;
307         RtlFreeHeap(GetProcessHeap(), 0, buffer);
308     } while (need_more_memory);
309
310     return status;
311 }
312
313
314 /******************************************************************************
315  *  NtDuplicateObject           [NTDLL.@]
316  *  ZwDuplicateObject           [NTDLL.@]
317  */
318 NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
319                                    HANDLE dest_process, PHANDLE dest,
320                                    ACCESS_MASK access, ULONG attributes, ULONG options )
321 {
322     NTSTATUS ret;
323     SERVER_START_REQ( dup_handle )
324     {
325         req->src_process = wine_server_obj_handle( source_process );
326         req->src_handle  = wine_server_obj_handle( source );
327         req->dst_process = wine_server_obj_handle( dest_process );
328         req->access      = access;
329         req->attributes  = attributes;
330         req->options     = options;
331
332         if (!(ret = wine_server_call( req )))
333         {
334             if (dest) *dest = wine_server_ptr_handle( reply->handle );
335             if (reply->closed)
336             {
337                 if (reply->self)
338                 {
339                     int fd = server_remove_fd_from_cache( source );
340                     if (fd != -1) close( fd );
341                 }
342             }
343             else if (options & DUPLICATE_CLOSE_SOURCE)
344                 WARN( "failed to close handle %p in process %p\n", source, source_process );
345         }
346     }
347     SERVER_END_REQ;
348     return ret;
349 }
350
351 /**************************************************************************
352  *                 NtClose                              [NTDLL.@]
353  *
354  * Close a handle reference to an object.
355  * 
356  * PARAMS
357  *  Handle [I] handle to close
358  *
359  * RETURNS
360  *  Success: ERROR_SUCCESS.
361  *  Failure: An NTSTATUS error code.
362  */
363 NTSTATUS WINAPI NtClose( HANDLE Handle )
364 {
365     NTSTATUS ret;
366     int fd = server_remove_fd_from_cache( Handle );
367
368     SERVER_START_REQ( close_handle )
369     {
370         req->handle = wine_server_obj_handle( Handle );
371         ret = wine_server_call( req );
372     }
373     SERVER_END_REQ;
374     if (fd != -1) close( fd );
375     return ret;
376 }
377
378 /*
379  *      Directory functions
380  */
381
382 /**************************************************************************
383  * NtOpenDirectoryObject [NTDLL.@]
384  * ZwOpenDirectoryObject [NTDLL.@]
385  *
386  * Open a namespace directory object.
387  * 
388  * PARAMS
389  *  DirectoryHandle  [O] Destination for the new directory handle
390  *  DesiredAccess    [I] Desired access to the directory
391  *  ObjectAttributes [I] Structure describing the directory
392  *
393  * RETURNS
394  *  Success: ERROR_SUCCESS.
395  *  Failure: An NTSTATUS error code.
396  */
397 NTSTATUS WINAPI NtOpenDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
398                                       POBJECT_ATTRIBUTES ObjectAttributes)
399 {
400     NTSTATUS ret;
401     TRACE("(%p,0x%08x,%s)\n", DirectoryHandle, DesiredAccess, debugstr_ObjectAttributes(ObjectAttributes));
402
403     if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
404     if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
405     /* Have to test it here because server won't know difference between
406      * ObjectName == NULL and ObjectName == "" */
407     if (!ObjectAttributes->ObjectName)
408     {
409         if (ObjectAttributes->RootDirectory)
410             return STATUS_OBJECT_NAME_INVALID;
411         else
412             return STATUS_OBJECT_PATH_SYNTAX_BAD;
413     }
414
415     SERVER_START_REQ(open_directory)
416     {
417         req->access = DesiredAccess;
418         req->attributes = ObjectAttributes->Attributes;
419         req->rootdir = wine_server_obj_handle( ObjectAttributes->RootDirectory );
420         if (ObjectAttributes->ObjectName)
421             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
422                                  ObjectAttributes->ObjectName->Length);
423         ret = wine_server_call( req );
424         *DirectoryHandle = wine_server_ptr_handle( reply->handle );
425     }
426     SERVER_END_REQ;
427     return ret;
428 }
429
430 /******************************************************************************
431  *  NtCreateDirectoryObject     [NTDLL.@]
432  *  ZwCreateDirectoryObject     [NTDLL.@]
433  *
434  * Create a namespace directory object.
435  * 
436  * PARAMS
437  *  DirectoryHandle  [O] Destination for the new directory handle
438  *  DesiredAccess    [I] Desired access to the directory
439  *  ObjectAttributes [I] Structure describing the directory
440  *
441  * RETURNS
442  *  Success: ERROR_SUCCESS.
443  *  Failure: An NTSTATUS error code.
444  */
445 NTSTATUS WINAPI NtCreateDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
446                                         POBJECT_ATTRIBUTES ObjectAttributes)
447 {
448     NTSTATUS ret;
449     TRACE("(%p,0x%08x,%s)\n", DirectoryHandle, DesiredAccess, debugstr_ObjectAttributes(ObjectAttributes));
450
451     if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
452
453     SERVER_START_REQ(create_directory)
454     {
455         req->access = DesiredAccess;
456         req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
457         req->rootdir = wine_server_obj_handle( ObjectAttributes ? ObjectAttributes->RootDirectory : 0 );
458         if (ObjectAttributes && ObjectAttributes->ObjectName)
459             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
460                                  ObjectAttributes->ObjectName->Length);
461         ret = wine_server_call( req );
462         *DirectoryHandle = wine_server_ptr_handle( reply->handle );
463     }
464     SERVER_END_REQ;
465     return ret;
466 }
467
468 /******************************************************************************
469  * NtQueryDirectoryObject [NTDLL.@]
470  * ZwQueryDirectoryObject [NTDLL.@]
471  *
472  * Read information from a namespace directory.
473  * 
474  * PARAMS
475  *  handle        [I]   Handle to a directory object
476  *  buffer        [O]   Buffer to hold the read data
477  *  size          [I]   Size of the buffer in bytes
478  *  single_entry  [I]   If TRUE, return a single entry, if FALSE, return as many as fit in the buffer
479  *  restart       [I]   If TRUE, start scanning from the start, if FALSE, scan from Context
480  *  context       [I/O] Indicates what point of the directory the scan is at
481  *  ret_size      [O]   Caller supplied storage for the number of bytes written (or NULL)
482  *
483  * RETURNS
484  *  Success: ERROR_SUCCESS.
485  *  Failure: An NTSTATUS error code.
486  */
487 NTSTATUS WINAPI NtQueryDirectoryObject(HANDLE handle, PDIRECTORY_BASIC_INFORMATION buffer,
488                                        ULONG size, BOOLEAN single_entry, BOOLEAN restart,
489                                        PULONG context, PULONG ret_size)
490 {
491     NTSTATUS ret;
492
493     if (restart) *context = 0;
494
495     if (single_entry)
496     {
497         if (size <= sizeof(*buffer) + 2*sizeof(WCHAR)) return STATUS_BUFFER_OVERFLOW;
498
499         SERVER_START_REQ( get_directory_entry )
500         {
501             req->handle = wine_server_obj_handle( handle );
502             req->index = *context;
503             wine_server_set_reply( req, buffer + 1, size - sizeof(*buffer) - 2*sizeof(WCHAR) );
504             if (!(ret = wine_server_call( req )))
505             {
506                 buffer->ObjectName.Buffer = (WCHAR *)(buffer + 1);
507                 buffer->ObjectName.Length = reply->name_len;
508                 buffer->ObjectName.MaximumLength = reply->name_len + sizeof(WCHAR);
509                 buffer->ObjectTypeName.Buffer = (WCHAR *)(buffer + 1) + reply->name_len/sizeof(WCHAR) + 1;
510                 buffer->ObjectTypeName.Length = wine_server_reply_size( reply ) - reply->name_len;
511                 buffer->ObjectTypeName.MaximumLength = buffer->ObjectTypeName.Length + sizeof(WCHAR);
512                 /* make room for the terminating null */
513                 memmove( buffer->ObjectTypeName.Buffer, buffer->ObjectTypeName.Buffer - 1,
514                          buffer->ObjectTypeName.Length );
515                 buffer->ObjectName.Buffer[buffer->ObjectName.Length/sizeof(WCHAR)] = 0;
516                 buffer->ObjectTypeName.Buffer[buffer->ObjectTypeName.Length/sizeof(WCHAR)] = 0;
517                 (*context)++;
518             }
519         }
520         SERVER_END_REQ;
521         if (ret_size)
522             *ret_size = buffer->ObjectName.MaximumLength + buffer->ObjectTypeName.MaximumLength + sizeof(*buffer);
523     }
524     else
525     {
526         FIXME("multiple entries not implemented\n");
527         ret = STATUS_NOT_IMPLEMENTED;
528     }
529
530     return ret;
531 }
532
533 /*
534  *      Link objects
535  */
536
537 /******************************************************************************
538  *  NtOpenSymbolicLinkObject    [NTDLL.@]
539  *  ZwOpenSymbolicLinkObject    [NTDLL.@]
540  *
541  * Open a namespace symbolic link object.
542  * 
543  * PARAMS
544  *  LinkHandle       [O] Destination for the new symbolic link handle
545  *  DesiredAccess    [I] Desired access to the symbolic link
546  *  ObjectAttributes [I] Structure describing the symbolic link
547  *
548  * RETURNS
549  *  Success: ERROR_SUCCESS.
550  *  Failure: An NTSTATUS error code.
551  */
552 NTSTATUS WINAPI NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, IN ACCESS_MASK DesiredAccess,
553                                          IN POBJECT_ATTRIBUTES ObjectAttributes)
554 {
555     NTSTATUS ret;
556     TRACE("(%p,0x%08x,%s)\n",LinkHandle, DesiredAccess, debugstr_ObjectAttributes(ObjectAttributes));
557
558     if (!LinkHandle) return STATUS_ACCESS_VIOLATION;
559     if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
560     /* Have to test it here because server won't know difference between
561      * ObjectName == NULL and ObjectName == "" */
562     if (!ObjectAttributes->ObjectName)
563     {
564         if (ObjectAttributes->RootDirectory)
565             return STATUS_OBJECT_NAME_INVALID;
566         else
567             return STATUS_OBJECT_PATH_SYNTAX_BAD;
568     }
569
570     SERVER_START_REQ(open_symlink)
571     {
572         req->access = DesiredAccess;
573         req->attributes = ObjectAttributes->Attributes;
574         req->rootdir = wine_server_obj_handle( ObjectAttributes->RootDirectory );
575         if (ObjectAttributes->ObjectName)
576             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
577                                  ObjectAttributes->ObjectName->Length);
578         ret = wine_server_call( req );
579         *LinkHandle = wine_server_ptr_handle( reply->handle );
580     }
581     SERVER_END_REQ;
582     return ret;
583 }
584
585 /******************************************************************************
586  *  NtCreateSymbolicLinkObject  [NTDLL.@]
587  *  ZwCreateSymbolicLinkObject  [NTDLL.@]
588  *
589  * Open a namespace symbolic link object.
590  * 
591  * PARAMS
592  *  SymbolicLinkHandle [O] Destination for the new symbolic link handle
593  *  DesiredAccess      [I] Desired access to the symbolic link
594  *  ObjectAttributes   [I] Structure describing the symbolic link
595  *  TargetName         [I] Name of the target symbolic link points to
596  *
597  * RETURNS
598  *  Success: ERROR_SUCCESS.
599  *  Failure: An NTSTATUS error code.
600  */
601 NTSTATUS WINAPI NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,IN ACCESS_MASK DesiredAccess,
602                                            IN POBJECT_ATTRIBUTES ObjectAttributes,
603                                            IN PUNICODE_STRING TargetName)
604 {
605     NTSTATUS ret;
606
607     if (!SymbolicLinkHandle || !TargetName) return STATUS_ACCESS_VIOLATION;
608     if (!TargetName->Buffer) return STATUS_INVALID_PARAMETER;
609
610     TRACE("(%p,0x%08x,%s -> %s)\n", SymbolicLinkHandle, DesiredAccess,
611           debugstr_ObjectAttributes(ObjectAttributes), debugstr_us(TargetName));
612
613     SERVER_START_REQ(create_symlink)
614     {
615         req->access = DesiredAccess;
616         req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
617         req->rootdir = wine_server_obj_handle( ObjectAttributes ? ObjectAttributes->RootDirectory : 0 );
618         if (ObjectAttributes && ObjectAttributes->ObjectName)
619         {
620             req->name_len = ObjectAttributes->ObjectName->Length;
621             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
622                                  ObjectAttributes->ObjectName->Length);
623         }
624         else
625             req->name_len = 0;
626         wine_server_add_data(req, TargetName->Buffer, TargetName->Length);
627         ret = wine_server_call( req );
628         *SymbolicLinkHandle = wine_server_ptr_handle( reply->handle );
629     }
630     SERVER_END_REQ;
631     return ret;
632 }
633
634 /******************************************************************************
635  *  NtQuerySymbolicLinkObject   [NTDLL.@]
636  *  ZwQuerySymbolicLinkObject   [NTDLL.@]
637  *
638  * Query a namespace symbolic link object target name.
639  *
640  * PARAMS
641  *  handle     [I] Handle to a symbolic link object
642  *  target     [O] Destination for the symbolic link target
643  *  length     [O] Size of returned data
644  *
645  * RETURNS
646  *  Success: ERROR_SUCCESS.
647  *  Failure: An NTSTATUS error code.
648  */
649 NTSTATUS WINAPI NtQuerySymbolicLinkObject( HANDLE handle, PUNICODE_STRING target, PULONG length )
650 {
651     NTSTATUS ret;
652
653     TRACE("(%p,%p,%p)\n", handle, target, length );
654
655     if (!target) return STATUS_ACCESS_VIOLATION;
656
657     SERVER_START_REQ(query_symlink)
658     {
659         req->handle = wine_server_obj_handle( handle );
660         if (target->MaximumLength >= sizeof(WCHAR))
661             wine_server_set_reply( req, target->Buffer, target->MaximumLength - sizeof(WCHAR) );
662         if (!(ret = wine_server_call( req )))
663         {
664             target->Length = wine_server_reply_size(reply);
665             target->Buffer[target->Length / sizeof(WCHAR)] = 0;
666             if (length) *length = reply->total + sizeof(WCHAR);
667         }
668         else if (length && ret == STATUS_BUFFER_TOO_SMALL) *length = reply->total + sizeof(WCHAR);
669     }
670     SERVER_END_REQ;
671     return ret;
672 }
673
674 /******************************************************************************
675  *  NtAllocateUuids   [NTDLL.@]
676  */
677 NTSTATUS WINAPI NtAllocateUuids(
678         PULARGE_INTEGER Time,
679         PULONG Range,
680         PULONG Sequence)
681 {
682         FIXME("(%p,%p,%p), stub.\n", Time, Range, Sequence);
683         return 0;
684 }
685
686 /**************************************************************************
687  *  NtMakeTemporaryObject       [NTDLL.@]
688  *  ZwMakeTemporaryObject       [NTDLL.@]
689  *
690  * Make a permanent object temporary.
691  *
692  * PARAMS
693  *  Handle [I] handle to permanent object
694  *
695  * RETURNS
696  *  Success: STATUS_SUCCESS.
697  *  Failure: An NTSTATUS error code.
698  */
699 NTSTATUS WINAPI NtMakeTemporaryObject( HANDLE Handle )
700 {
701     FIXME("(%p), stub.\n", Handle);
702     return STATUS_SUCCESS;
703 }