ntdll: Fix a compiler warning.
[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 = (POBJECT_BASIC_INFORMATION)ptr;
69
70             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
71
72             SERVER_START_REQ( get_object_info )
73             {
74                 req->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 ObjectDataInformation:
89         {
90             OBJECT_DATA_INFORMATION* p = (OBJECT_DATA_INFORMATION*)ptr;
91
92             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
93
94             SERVER_START_REQ( set_handle_info )
95             {
96                 req->handle = handle;
97                 req->flags  = 0;
98                 req->mask   = 0;
99                 status = wine_server_call( req );
100                 if (status == STATUS_SUCCESS)
101                 {
102                     p->InheritHandle = (reply->old_flags & HANDLE_FLAG_INHERIT) ? TRUE : FALSE;
103                     p->ProtectFromClose = (reply->old_flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ? TRUE : FALSE;
104                     if (used_len) *used_len = sizeof(*p);
105                 }
106             }
107             SERVER_END_REQ;
108         }
109         break;
110     default:
111         FIXME("Unsupported information class %u\n", info_class);
112         status = STATUS_NOT_IMPLEMENTED;
113         break;
114     }
115     return status;
116 }
117
118 /******************************************************************
119  *              NtSetInformationObject [NTDLL.@]
120  *              ZwSetInformationObject [NTDLL.@]
121  *
122  */
123 NTSTATUS WINAPI NtSetInformationObject(IN HANDLE handle,
124                                        IN OBJECT_INFORMATION_CLASS info_class,
125                                        IN PVOID ptr, IN ULONG len)
126 {
127     NTSTATUS status;
128
129     TRACE("(%p,0x%08x,%p,0x%08x): stub\n",
130           handle, info_class, ptr, len);
131
132     switch (info_class)
133     {
134     case ObjectDataInformation:
135         {
136             OBJECT_DATA_INFORMATION* p = (OBJECT_DATA_INFORMATION*)ptr;
137
138             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
139
140             SERVER_START_REQ( set_handle_info )
141             {
142                 req->handle = handle;
143                 req->flags  = 0;
144                 req->mask   = HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE;
145                 if (p->InheritHandle)    req->flags |= HANDLE_FLAG_INHERIT;
146                 if (p->ProtectFromClose) req->flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
147                 status = wine_server_call( req );
148             }
149             SERVER_END_REQ;
150         }
151         break;
152     default:
153         FIXME("Unsupported information class %u\n", info_class);
154         status = STATUS_NOT_IMPLEMENTED;
155         break;
156     }
157     return status;
158 }
159
160 /******************************************************************************
161  *  NtQuerySecurityObject       [NTDLL.@]
162  *
163  * An ntdll analogue to GetKernelObjectSecurity().
164  *
165  * NOTES
166  *  only the lowest 4 bit of SecurityObjectInformationClass are used
167  *  0x7-0xf returns STATUS_ACCESS_DENIED (even running with system privileges)
168  *
169  * FIXME
170  *  We are constructing a fake sid (Administrators:Full, System:Full, Everyone:Read)
171  */
172 NTSTATUS WINAPI
173 NtQuerySecurityObject(
174         IN HANDLE Object,
175         IN SECURITY_INFORMATION RequestedInformation,
176         OUT PSECURITY_DESCRIPTOR pSecurityDesriptor,
177         IN ULONG Length,
178         OUT PULONG ResultLength)
179 {
180         static const SID_IDENTIFIER_AUTHORITY localSidAuthority = {SECURITY_NT_AUTHORITY};
181         static const SID_IDENTIFIER_AUTHORITY worldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY};
182         BYTE Buffer[256];
183         PISECURITY_DESCRIPTOR_RELATIVE psd = (PISECURITY_DESCRIPTOR_RELATIVE)Buffer;
184         UINT BufferIndex = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
185
186         FIXME("(%p,0x%08x,%p,0x%08x,%p) stub!\n",
187         Object, RequestedInformation, pSecurityDesriptor, Length, ResultLength);
188
189         RequestedInformation &= 0x0000000f;
190
191         if (RequestedInformation & SACL_SECURITY_INFORMATION) return STATUS_ACCESS_DENIED;
192
193         ZeroMemory(Buffer, 256);
194         RtlCreateSecurityDescriptor((PSECURITY_DESCRIPTOR)psd, SECURITY_DESCRIPTOR_REVISION);
195         psd->Control = SE_SELF_RELATIVE |
196           ((RequestedInformation & DACL_SECURITY_INFORMATION) ? SE_DACL_PRESENT:0);
197
198         /* owner: administrator S-1-5-20-220*/
199         if (OWNER_SECURITY_INFORMATION & RequestedInformation)
200         {
201           SID* psid = (SID*)&(Buffer[BufferIndex]);
202
203           psd->Owner = BufferIndex;
204           BufferIndex += RtlLengthRequiredSid(2);
205
206           psid->Revision = SID_REVISION;
207           psid->SubAuthorityCount = 2;
208           psid->IdentifierAuthority = localSidAuthority;
209           psid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
210           psid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
211         }
212
213         /* group: built in domain S-1-5-12 */
214         if (GROUP_SECURITY_INFORMATION & RequestedInformation)
215         {
216           SID* psid = (SID*) &(Buffer[BufferIndex]);
217
218           psd->Group = BufferIndex;
219           BufferIndex += RtlLengthRequiredSid(1);
220
221           psid->Revision = SID_REVISION;
222           psid->SubAuthorityCount = 1;
223           psid->IdentifierAuthority = localSidAuthority;
224           psid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
225         }
226
227         /* discretionary ACL */
228         if (DACL_SECURITY_INFORMATION & RequestedInformation)
229         {
230           /* acl header */
231           PACL pacl = (PACL)&(Buffer[BufferIndex]);
232           PACCESS_ALLOWED_ACE pace;
233           SID* psid;
234
235           psd->Dacl = BufferIndex;
236
237           pacl->AclRevision = MIN_ACL_REVISION;
238           pacl->AceCount = 3;
239           pacl->AclSize = BufferIndex; /* storing the start index temporary */
240
241           BufferIndex += sizeof(ACL);
242
243           /* ACE System - full access */
244           pace = (PACCESS_ALLOWED_ACE)&(Buffer[BufferIndex]);
245           BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
246
247           pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
248           pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
249           pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(1);
250           pace->Mask = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER  | 0x3f;
251           pace->SidStart = BufferIndex;
252
253           /* SID S-1-5-12 (System) */
254           psid = (SID*)&(Buffer[BufferIndex]);
255
256           BufferIndex += RtlLengthRequiredSid(1);
257
258           psid->Revision = SID_REVISION;
259           psid->SubAuthorityCount = 1;
260           psid->IdentifierAuthority = localSidAuthority;
261           psid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
262
263           /* ACE Administrators - full access*/
264           pace = (PACCESS_ALLOWED_ACE) &(Buffer[BufferIndex]);
265           BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
266
267           pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
268           pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
269           pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(2);
270           pace->Mask = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER  | 0x3f;
271           pace->SidStart = BufferIndex;
272
273           /* S-1-5-12 (Administrators) */
274           psid = (SID*)&(Buffer[BufferIndex]);
275
276           BufferIndex += RtlLengthRequiredSid(2);
277
278           psid->Revision = SID_REVISION;
279           psid->SubAuthorityCount = 2;
280           psid->IdentifierAuthority = localSidAuthority;
281           psid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
282           psid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
283
284           /* ACE Everyone - read access */
285           pace = (PACCESS_ALLOWED_ACE)&(Buffer[BufferIndex]);
286           BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
287
288           pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
289           pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
290           pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(1);
291           pace->Mask = READ_CONTROL| 0x19;
292           pace->SidStart = BufferIndex;
293
294           /* SID S-1-1-0 (Everyone) */
295           psid = (SID*)&(Buffer[BufferIndex]);
296
297           BufferIndex += RtlLengthRequiredSid(1);
298
299           psid->Revision = SID_REVISION;
300           psid->SubAuthorityCount = 1;
301           psid->IdentifierAuthority = worldSidAuthority;
302           psid->SubAuthority[0] = 0;
303
304           /* calculate used bytes */
305           pacl->AclSize = BufferIndex - pacl->AclSize;
306         }
307         *ResultLength = BufferIndex;
308         TRACE("len=%u\n", *ResultLength);
309         if (Length < *ResultLength) return STATUS_BUFFER_TOO_SMALL;
310         memcpy(pSecurityDesriptor, Buffer, *ResultLength);
311
312         return STATUS_SUCCESS;
313 }
314
315
316 /******************************************************************************
317  *  NtDuplicateObject           [NTDLL.@]
318  *  ZwDuplicateObject           [NTDLL.@]
319  */
320 NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
321                                    HANDLE dest_process, PHANDLE dest,
322                                    ACCESS_MASK access, ULONG attributes, ULONG options )
323 {
324     NTSTATUS ret;
325     SERVER_START_REQ( dup_handle )
326     {
327         req->src_process = source_process;
328         req->src_handle  = source;
329         req->dst_process = dest_process;
330         req->access      = access;
331         req->attributes  = attributes;
332         req->options     = options;
333
334         if (!(ret = wine_server_call( req )))
335         {
336             if (dest) *dest = reply->handle;
337             if (reply->closed)
338             {
339                 if (reply->self)
340                 {
341                     int fd = server_remove_fd_from_cache( source );
342                     if (fd != -1) close( fd );
343                 }
344             }
345             else if (options & DUPLICATE_CLOSE_SOURCE)
346                 WARN( "failed to close handle %p in process %p\n", source, source_process );
347         }
348     }
349     SERVER_END_REQ;
350     return ret;
351 }
352
353 /**************************************************************************
354  *                 NtClose                              [NTDLL.@]
355  *
356  * Close a handle reference to an object.
357  * 
358  * PARAMS
359  *  Handle [I] handle to close
360  *
361  * RETURNS
362  *  Success: ERROR_SUCCESS.
363  *  Failure: An NTSTATUS error code.
364  */
365 NTSTATUS WINAPI NtClose( HANDLE Handle )
366 {
367     NTSTATUS ret;
368     int fd = server_remove_fd_from_cache( Handle );
369
370     SERVER_START_REQ( close_handle )
371     {
372         req->handle = Handle;
373         ret = wine_server_call( req );
374     }
375     SERVER_END_REQ;
376     if (fd != -1) close( fd );
377     return ret;
378 }
379
380 /*
381  *      Directory functions
382  */
383
384 /**************************************************************************
385  * NtOpenDirectoryObject [NTDLL.@]
386  * ZwOpenDirectoryObject [NTDLL.@]
387  *
388  * Open a namespace directory object.
389  * 
390  * PARAMS
391  *  DirectoryHandle  [O] Destination for the new directory handle
392  *  DesiredAccess    [I] Desired access to the directory
393  *  ObjectAttributes [I] Structure describing the directory
394  *
395  * RETURNS
396  *  Success: ERROR_SUCCESS.
397  *  Failure: An NTSTATUS error code.
398  */
399 NTSTATUS WINAPI NtOpenDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
400                                       POBJECT_ATTRIBUTES ObjectAttributes)
401 {
402     NTSTATUS ret;
403     TRACE("(%p,0x%08x)\n", DirectoryHandle, DesiredAccess);
404     dump_ObjectAttributes(ObjectAttributes);
405
406     if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
407     if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
408     /* Have to test it here because server won't know difference between
409      * ObjectName == NULL and ObjectName == "" */
410     if (!ObjectAttributes->ObjectName)
411     {
412         if (ObjectAttributes->RootDirectory)
413             return STATUS_OBJECT_NAME_INVALID;
414         else
415             return STATUS_OBJECT_PATH_SYNTAX_BAD;
416     }
417
418     SERVER_START_REQ(open_directory)
419     {
420         req->access = DesiredAccess;
421         req->attributes = ObjectAttributes->Attributes;
422         req->rootdir = ObjectAttributes->RootDirectory;
423         if (ObjectAttributes->ObjectName)
424             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
425                                  ObjectAttributes->ObjectName->Length);
426         ret = wine_server_call( req );
427         *DirectoryHandle = reply->handle;
428     }
429     SERVER_END_REQ;
430     return ret;
431 }
432
433 /******************************************************************************
434  *  NtCreateDirectoryObject     [NTDLL.@]
435  *  ZwCreateDirectoryObject     [NTDLL.@]
436  *
437  * Create a namespace directory object.
438  * 
439  * PARAMS
440  *  DirectoryHandle  [O] Destination for the new directory handle
441  *  DesiredAccess    [I] Desired access to the directory
442  *  ObjectAttributes [I] Structure describing the directory
443  *
444  * RETURNS
445  *  Success: ERROR_SUCCESS.
446  *  Failure: An NTSTATUS error code.
447  */
448 NTSTATUS WINAPI NtCreateDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
449                                         POBJECT_ATTRIBUTES ObjectAttributes)
450 {
451     NTSTATUS ret;
452     TRACE("(%p,0x%08x)\n", DirectoryHandle, DesiredAccess);
453     dump_ObjectAttributes(ObjectAttributes);
454
455     if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
456
457     SERVER_START_REQ(create_directory)
458     {
459         req->access = DesiredAccess;
460         req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
461         req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0;
462         if (ObjectAttributes && ObjectAttributes->ObjectName)
463             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
464                                  ObjectAttributes->ObjectName->Length);
465         ret = wine_server_call( req );
466         *DirectoryHandle = reply->handle;
467     }
468     SERVER_END_REQ;
469     return ret;
470 }
471
472 /******************************************************************************
473  * NtQueryDirectoryObject [NTDLL.@]
474  * ZwQueryDirectoryObject [NTDLL.@]
475  *
476  * Read information from a namespace directory.
477  * 
478  * PARAMS
479  *  DirectoryHandle   [I]   Handle to a directory object
480  *  Buffer            [O]   Buffer to hold the read data
481  *  BufferLength      [I]   Size of the buffer in bytes
482  *  ReturnSingleEntry [I]   If TRUE, return a single entry, if FALSE, return as many as fit in the buffer
483  *  RestartScan       [I]   If TRUE, start scanning from the start, if FALSE, scan from Context
484  *  Context           [I/O] Indicates what point of the directory the scan is at
485  *  ReturnLength      [O]   Caller supplied storage for the number of bytes written (or NULL)
486  *
487  * RETURNS
488  *  Success: ERROR_SUCCESS.
489  *  Failure: An NTSTATUS error code.
490  */
491 NTSTATUS WINAPI NtQueryDirectoryObject(IN HANDLE DirectoryHandle, OUT PDIRECTORY_BASIC_INFORMATION Buffer,
492                                        IN ULONG BufferLength, IN BOOLEAN ReturnSingleEntry, IN BOOLEAN RestartScan,
493                                        IN OUT PULONG Context, OUT PULONG ReturnLength OPTIONAL)
494 {
495     FIXME("(%p,%p,0x%08x,0x%08x,0x%08x,%p,%p), stub\n", DirectoryHandle, Buffer, BufferLength, ReturnSingleEntry,
496           RestartScan, Context, ReturnLength);
497
498     return STATUS_NOT_IMPLEMENTED;
499 }
500
501 /*
502  *      Link objects
503  */
504
505 /******************************************************************************
506  *  NtOpenSymbolicLinkObject    [NTDLL.@]
507  *  ZwOpenSymbolicLinkObject    [NTDLL.@]
508  *
509  * Open a namespace symbolic link object.
510  * 
511  * PARAMS
512  *  LinkHandle       [O] Destination for the new symbolic link handle
513  *  DesiredAccess    [I] Desired access to the symbolic link
514  *  ObjectAttributes [I] Structure describing the symbolic link
515  *
516  * RETURNS
517  *  Success: ERROR_SUCCESS.
518  *  Failure: An NTSTATUS error code.
519  */
520 NTSTATUS WINAPI NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, IN ACCESS_MASK DesiredAccess,
521                                          IN POBJECT_ATTRIBUTES ObjectAttributes)
522 {
523     NTSTATUS ret;
524     TRACE("(%p,0x%08x,%p)\n",LinkHandle, DesiredAccess, ObjectAttributes);
525     dump_ObjectAttributes(ObjectAttributes);
526
527     if (!LinkHandle) return STATUS_ACCESS_VIOLATION;
528     if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
529     /* Have to test it here because server won't know difference between
530      * ObjectName == NULL and ObjectName == "" */
531     if (!ObjectAttributes->ObjectName)
532     {
533         if (ObjectAttributes->RootDirectory)
534             return STATUS_OBJECT_NAME_INVALID;
535         else
536             return STATUS_OBJECT_PATH_SYNTAX_BAD;
537     }
538
539     SERVER_START_REQ(open_symlink)
540     {
541         req->access = DesiredAccess;
542         req->attributes = ObjectAttributes->Attributes;
543         req->rootdir = ObjectAttributes->RootDirectory;
544         if (ObjectAttributes->ObjectName)
545             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
546                                  ObjectAttributes->ObjectName->Length);
547         ret = wine_server_call( req );
548         *LinkHandle = reply->handle;
549     }
550     SERVER_END_REQ;
551     return ret;
552 }
553
554 /******************************************************************************
555  *  NtCreateSymbolicLinkObject  [NTDLL.@]
556  *  ZwCreateSymbolicLinkObject  [NTDLL.@]
557  *
558  * Open a namespace symbolic link object.
559  * 
560  * PARAMS
561  *  SymbolicLinkHandle [O] Destination for the new symbolic link handle
562  *  DesiredAccess      [I] Desired access to the symbolic link
563  *  ObjectAttributes   [I] Structure describing the symbolic link
564  *  TargetName         [I] Name of the target symbolic link points to
565  *
566  * RETURNS
567  *  Success: ERROR_SUCCESS.
568  *  Failure: An NTSTATUS error code.
569  */
570 NTSTATUS WINAPI NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,IN ACCESS_MASK DesiredAccess,
571                                            IN POBJECT_ATTRIBUTES ObjectAttributes,
572                                            IN PUNICODE_STRING TargetName)
573 {
574     NTSTATUS ret;
575     TRACE("(%p,0x%08x,%p, -> %s)\n", SymbolicLinkHandle, DesiredAccess, ObjectAttributes,
576                                       debugstr_us(TargetName));
577     dump_ObjectAttributes(ObjectAttributes);
578
579     if (!SymbolicLinkHandle || !TargetName) return STATUS_ACCESS_VIOLATION;
580     if (!TargetName->Buffer) return STATUS_INVALID_PARAMETER;
581
582     SERVER_START_REQ(create_symlink)
583     {
584         req->access = DesiredAccess;
585         req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
586         req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0;
587         if (ObjectAttributes && ObjectAttributes->ObjectName)
588         {
589             req->name_len = ObjectAttributes->ObjectName->Length;
590             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
591                                  ObjectAttributes->ObjectName->Length);
592         }
593         else
594             req->name_len = 0;
595         wine_server_add_data(req, TargetName->Buffer, TargetName->Length);
596         ret = wine_server_call( req );
597         *SymbolicLinkHandle = reply->handle;
598     }
599     SERVER_END_REQ;
600     return ret;
601 }
602
603 /******************************************************************************
604  *  NtQuerySymbolicLinkObject   [NTDLL.@]
605  *  ZwQuerySymbolicLinkObject   [NTDLL.@]
606  *
607  * Query a namespace symbolic link object target name.
608  * 
609  * PARAMS
610  *  LinkHandle     [I] Handle to a symbolic link object
611  *  LinkTarget     [O] Destination for the symbolic link target
612  *  ReturnedLength [O] Size of returned data
613  *
614  * RETURNS
615  *  Success: ERROR_SUCCESS.
616  *  Failure: An NTSTATUS error code.
617  */
618 NTSTATUS WINAPI NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, IN OUT PUNICODE_STRING LinkTarget,
619                                           OUT PULONG ReturnedLength OPTIONAL)
620 {
621     NTSTATUS ret;
622     TRACE("(%p,%p,%p)\n", LinkHandle, LinkTarget, ReturnedLength);
623
624     if (!LinkTarget) return STATUS_ACCESS_VIOLATION;
625
626     SERVER_START_REQ(query_symlink)
627     {
628         req->handle = LinkHandle;
629         wine_server_set_reply( req, LinkTarget->Buffer, LinkTarget->MaximumLength );
630         if (!(ret = wine_server_call( req )))
631         {
632             LinkTarget->Length = wine_server_reply_size(reply);
633             if (ReturnedLength) *ReturnedLength = LinkTarget->Length;
634         }
635     }
636     SERVER_END_REQ;
637     return ret;
638 }
639
640 /******************************************************************************
641  *  NtAllocateUuids   [NTDLL.@]
642  */
643 NTSTATUS WINAPI NtAllocateUuids(
644         PULARGE_INTEGER Time,
645         PULONG Range,
646         PULONG Sequence)
647 {
648         FIXME("(%p,%p,%p), stub.\n", Time, Range, Sequence);
649         return 0;
650 }