ntdll: Properly handle empty but present ACLs in self-relative descriptors.
[wine] / dlls / ntdll / reg.c
1 /*
2  * Registry functions
3  *
4  * Copyright (C) 1999 Juergen Schmied
5  * Copyright (C) 2000 Alexandre Julliard
6  * Copyright 2005 Ivan Leo Puoti, Laurent Pinchart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * NOTES:
23  *      HKEY_LOCAL_MACHINE      \\REGISTRY\\MACHINE
24  *      HKEY_USERS              \\REGISTRY\\USER
25  *      HKEY_CURRENT_CONFIG     \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
26   *     HKEY_CLASSES            \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "wine/library.h"
39 #include "ntdll_misc.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44
45 /* maximum length of a key/value name in bytes (without terminating null) */
46 #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
47
48 /******************************************************************************
49  * NtCreateKey [NTDLL.@]
50  * ZwCreateKey [NTDLL.@]
51  */
52 NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
53                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
54                              PULONG dispos )
55 {
56     NTSTATUS ret;
57
58     if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
59     if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
60     if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
61
62     TRACE( "(%p,%s,%s,%x,%x,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
63            debugstr_us(class), options, access, retkey );
64
65     SERVER_START_REQ( create_key )
66     {
67         req->parent     = wine_server_obj_handle( attr->RootDirectory );
68         req->access     = access;
69         req->attributes = attr->Attributes;
70         req->options    = options;
71         req->namelen    = attr->ObjectName->Length;
72         wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
73         if (class) wine_server_add_data( req, class->Buffer, class->Length );
74         if (!(ret = wine_server_call( req )))
75         {
76             *retkey = wine_server_ptr_handle( reply->hkey );
77             if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
78         }
79     }
80     SERVER_END_REQ;
81     TRACE("<- %p\n", *retkey);
82     return ret;
83 }
84
85 /******************************************************************************
86  *  RtlpNtCreateKey [NTDLL.@]
87  *
88  *  See NtCreateKey.
89  */
90 NTSTATUS WINAPI RtlpNtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
91                                  ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
92                                  PULONG dispos )
93 {
94     OBJECT_ATTRIBUTES oa;
95
96     if (attr)
97     {
98         oa = *attr;
99         oa.Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
100         attr = &oa;
101     }
102
103     return NtCreateKey(retkey, access, attr, 0, NULL, 0, dispos);
104 }
105
106 /******************************************************************************
107  * NtOpenKey [NTDLL.@]
108  * ZwOpenKey [NTDLL.@]
109  *
110  *   OUT        HANDLE                  retkey (returns 0 when failure)
111  *   IN         ACCESS_MASK             access
112  *   IN         POBJECT_ATTRIBUTES      attr
113  */
114 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
115 {
116     NTSTATUS ret;
117     DWORD len;
118
119     if (!retkey || !attr) return STATUS_ACCESS_VIOLATION;
120     if (attr->Length > sizeof(OBJECT_ATTRIBUTES)) return STATUS_INVALID_PARAMETER;
121     len = attr->ObjectName->Length;
122     TRACE( "(%p,%s,%x,%p)\n", attr->RootDirectory,
123            debugstr_us(attr->ObjectName), access, retkey );
124
125     if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
126
127     SERVER_START_REQ( open_key )
128     {
129         req->parent     = wine_server_obj_handle( attr->RootDirectory );
130         req->access     = access;
131         req->attributes = attr->Attributes;
132         wine_server_add_data( req, attr->ObjectName->Buffer, len );
133         ret = wine_server_call( req );
134         *retkey = wine_server_ptr_handle( reply->hkey );
135     }
136     SERVER_END_REQ;
137     TRACE("<- %p\n", *retkey);
138     return ret;
139 }
140
141 /******************************************************************************
142  * RtlpNtOpenKey [NTDLL.@]
143  *
144  * See NtOpenKey.
145  */
146 NTSTATUS WINAPI RtlpNtOpenKey( PHANDLE retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
147 {
148     if (attr)
149         attr->Attributes &= ~(OBJ_PERMANENT|OBJ_EXCLUSIVE);
150     return NtOpenKey(retkey, access, attr);
151 }
152
153 /******************************************************************************
154  * NtDeleteKey [NTDLL.@]
155  * ZwDeleteKey [NTDLL.@]
156  */
157 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
158 {
159     NTSTATUS ret;
160
161     TRACE( "(%p)\n", hkey );
162
163     SERVER_START_REQ( delete_key )
164     {
165         req->hkey = wine_server_obj_handle( hkey );
166         ret = wine_server_call( req );
167     }
168     SERVER_END_REQ;
169     return ret;
170 }
171
172 /******************************************************************************
173  * RtlpNtMakeTemporaryKey [NTDLL.@]
174  *
175  *  See NtDeleteKey.
176  */
177 NTSTATUS WINAPI RtlpNtMakeTemporaryKey( HANDLE hkey )
178 {
179     return NtDeleteKey(hkey);
180 }
181
182 /******************************************************************************
183  * NtDeleteValueKey [NTDLL.@]
184  * ZwDeleteValueKey [NTDLL.@]
185  */
186 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
187 {
188     NTSTATUS ret;
189
190     TRACE( "(%p,%s)\n", hkey, debugstr_us(name) );
191     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
192
193     SERVER_START_REQ( delete_key_value )
194     {
195         req->hkey = wine_server_obj_handle( hkey );
196         wine_server_add_data( req, name->Buffer, name->Length );
197         ret = wine_server_call( req );
198     }
199     SERVER_END_REQ;
200     return ret;
201 }
202
203
204 /******************************************************************************
205  *     enumerate_key
206  *
207  * Implementation of NtQueryKey and NtEnumerateKey
208  */
209 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
210                                void *info, DWORD length, DWORD *result_len )
211
212 {
213     NTSTATUS ret;
214     void *data_ptr;
215     size_t fixed_size;
216
217     switch(info_class)
218     {
219     case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
220     case KeyFullInformation:  data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
221     case KeyNodeInformation:  data_ptr = ((KEY_NODE_INFORMATION *)info)->Name;  break;
222     case KeyNameInformation:  data_ptr = ((KEY_NAME_INFORMATION *)info)->Name;  break;
223     default:
224         FIXME( "Information class %d not implemented\n", info_class );
225         return STATUS_INVALID_PARAMETER;
226     }
227     fixed_size = (char *)data_ptr - (char *)info;
228
229     SERVER_START_REQ( enum_key )
230     {
231         req->hkey       = wine_server_obj_handle( handle );
232         req->index      = index;
233         req->info_class = info_class;
234         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
235         if (!(ret = wine_server_call( req )))
236         {
237             switch(info_class)
238             {
239             case KeyBasicInformation:
240                 {
241                     KEY_BASIC_INFORMATION keyinfo;
242                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
243                     keyinfo.LastWriteTime.QuadPart = reply->modif;
244                     keyinfo.TitleIndex = 0;
245                     keyinfo.NameLength = reply->namelen;
246                     memcpy( info, &keyinfo, min( length, fixed_size ) );
247                 }
248                 break;
249             case KeyFullInformation:
250                 {
251                     KEY_FULL_INFORMATION keyinfo;
252                     fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
253                     keyinfo.LastWriteTime.QuadPart = reply->modif;
254                     keyinfo.TitleIndex = 0;
255                     keyinfo.ClassLength = wine_server_reply_size(reply);
256                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
257                     keyinfo.SubKeys = reply->subkeys;
258                     keyinfo.MaxNameLen = reply->max_subkey;
259                     keyinfo.MaxClassLen = reply->max_class;
260                     keyinfo.Values = reply->values;
261                     keyinfo.MaxValueNameLen = reply->max_value;
262                     keyinfo.MaxValueDataLen = reply->max_data;
263                     memcpy( info, &keyinfo, min( length, fixed_size ) );
264                 }
265                 break;
266             case KeyNodeInformation:
267                 {
268                     KEY_NODE_INFORMATION keyinfo;
269                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
270                     keyinfo.LastWriteTime.QuadPart = reply->modif;
271                     keyinfo.TitleIndex = 0;
272                     if (reply->namelen < wine_server_reply_size(reply))
273                     {
274                         keyinfo.ClassLength = wine_server_reply_size(reply) - reply->namelen;
275                         keyinfo.ClassOffset = fixed_size + reply->namelen;
276                     }
277                     else
278                     {
279                         keyinfo.ClassLength = 0;
280                         keyinfo.ClassOffset = -1;
281                     }
282                     keyinfo.NameLength = reply->namelen;
283                     memcpy( info, &keyinfo, min( length, fixed_size ) );
284                 }
285                 break;
286             case KeyNameInformation:
287                 {
288                     KEY_NAME_INFORMATION keyinfo;
289                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
290                     keyinfo.NameLength = reply->namelen;
291                     memcpy( info, &keyinfo, min( length, fixed_size ) );
292                 }
293                 break;
294             }
295             *result_len = fixed_size + reply->total;
296             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
297         }
298     }
299     SERVER_END_REQ;
300     return ret;
301 }
302
303
304
305 /******************************************************************************
306  * NtEnumerateKey [NTDLL.@]
307  * ZwEnumerateKey [NTDLL.@]
308  *
309  * NOTES
310  *  the name copied into the buffer is NOT 0-terminated
311  */
312 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
313                                 void *info, DWORD length, DWORD *result_len )
314 {
315     /* -1 means query key, so avoid it here */
316     if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
317     return enumerate_key( handle, index, info_class, info, length, result_len );
318 }
319
320
321 /******************************************************************************
322  * RtlpNtEnumerateSubKey [NTDLL.@]
323  *
324  */
325 NTSTATUS WINAPI RtlpNtEnumerateSubKey( HANDLE handle, UNICODE_STRING *out, ULONG index )
326 {
327   KEY_BASIC_INFORMATION *info;
328   DWORD dwLen, dwResultLen;
329   NTSTATUS ret;
330
331   if (out->Length)
332   {
333     dwLen = out->Length + sizeof(KEY_BASIC_INFORMATION);
334     info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
335     if (!info)
336       return STATUS_NO_MEMORY;
337   }
338   else
339   {
340     dwLen = 0;
341     info = NULL;
342   }
343
344   ret = NtEnumerateKey( handle, index, KeyBasicInformation, info, dwLen, &dwResultLen );
345   dwResultLen -= sizeof(KEY_BASIC_INFORMATION);
346
347   if (ret == STATUS_BUFFER_OVERFLOW)
348     out->Length = dwResultLen;
349   else if (!ret)
350   {
351     if (out->Length < info->NameLength)
352     {
353       out->Length = dwResultLen;
354       ret = STATUS_BUFFER_OVERFLOW;
355     }
356     else
357     {
358       out->Length = info->NameLength;
359       memcpy(out->Buffer, info->Name, info->NameLength);
360     }
361   }
362
363   RtlFreeHeap( GetProcessHeap(), 0, info );
364   return ret;
365 }
366
367 /******************************************************************************
368  * NtQueryKey [NTDLL.@]
369  * ZwQueryKey [NTDLL.@]
370  */
371 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
372                             void *info, DWORD length, DWORD *result_len )
373 {
374     return enumerate_key( handle, -1, info_class, info, length, result_len );
375 }
376
377
378 /* fill the key value info structure for a specific info class */
379 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
380                                  DWORD length, int type, int name_len, int data_len )
381 {
382     switch(info_class)
383     {
384     case KeyValueBasicInformation:
385         {
386             KEY_VALUE_BASIC_INFORMATION keyinfo;
387             keyinfo.TitleIndex = 0;
388             keyinfo.Type       = type;
389             keyinfo.NameLength = name_len;
390             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
391             memcpy( info, &keyinfo, length );
392             break;
393         }
394     case KeyValueFullInformation:
395         {
396             KEY_VALUE_FULL_INFORMATION keyinfo;
397             keyinfo.TitleIndex = 0;
398             keyinfo.Type       = type;
399             keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
400             keyinfo.DataLength = data_len;
401             keyinfo.NameLength = name_len;
402             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
403             memcpy( info, &keyinfo, length );
404             break;
405         }
406     case KeyValuePartialInformation:
407         {
408             KEY_VALUE_PARTIAL_INFORMATION keyinfo;
409             keyinfo.TitleIndex = 0;
410             keyinfo.Type       = type;
411             keyinfo.DataLength = data_len;
412             length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
413             memcpy( info, &keyinfo, length );
414             break;
415         }
416     default:
417         break;
418     }
419 }
420
421
422 /******************************************************************************
423  *  NtEnumerateValueKey [NTDLL.@]
424  *  ZwEnumerateValueKey [NTDLL.@]
425  */
426 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
427                                      KEY_VALUE_INFORMATION_CLASS info_class,
428                                      void *info, DWORD length, DWORD *result_len )
429 {
430     NTSTATUS ret;
431     void *ptr;
432     size_t fixed_size;
433
434     TRACE( "(%p,%u,%d,%p,%d)\n", handle, index, info_class, info, length );
435
436     /* compute the length we want to retrieve */
437     switch(info_class)
438     {
439     case KeyValueBasicInformation:   ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
440     case KeyValueFullInformation:    ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
441     case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
442     default:
443         FIXME( "Information class %d not implemented\n", info_class );
444         return STATUS_INVALID_PARAMETER;
445     }
446     fixed_size = (char *)ptr - (char *)info;
447
448     SERVER_START_REQ( enum_key_value )
449     {
450         req->hkey       = wine_server_obj_handle( handle );
451         req->index      = index;
452         req->info_class = info_class;
453         if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
454         if (!(ret = wine_server_call( req )))
455         {
456             copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
457                                  wine_server_reply_size(reply) - reply->namelen );
458             *result_len = fixed_size + reply->total;
459             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
460         }
461     }
462     SERVER_END_REQ;
463     return ret;
464 }
465
466
467 /******************************************************************************
468  * NtQueryValueKey [NTDLL.@]
469  * ZwQueryValueKey [NTDLL.@]
470  *
471  * NOTES
472  *  the name in the KeyValueInformation is never set
473  */
474 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
475                                  KEY_VALUE_INFORMATION_CLASS info_class,
476                                  void *info, DWORD length, DWORD *result_len )
477 {
478     NTSTATUS ret;
479     UCHAR *data_ptr;
480     unsigned int fixed_size = 0, min_size = 0;
481
482     TRACE( "(%p,%s,%d,%p,%d)\n", handle, debugstr_us(name), info_class, info, length );
483
484     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
485
486     /* compute the length we want to retrieve */
487     switch(info_class)
488     {
489     case KeyValueBasicInformation:
490     {
491         KEY_VALUE_BASIC_INFORMATION *basic_info = info;
492         min_size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name);
493         fixed_size = min_size + name->Length;
494         if (min_size < length)
495             memcpy(basic_info->Name, name->Buffer, min(length - min_size, name->Length));
496         data_ptr = NULL;
497         break;
498     }
499     case KeyValueFullInformation:
500     {
501         KEY_VALUE_FULL_INFORMATION *full_info = info;
502         min_size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
503         fixed_size = min_size + name->Length;
504         if (min_size < length)
505             memcpy(full_info->Name, name->Buffer, min(length - min_size, name->Length));
506         data_ptr = (UCHAR *)full_info->Name + name->Length;
507         break;
508     }
509     case KeyValuePartialInformation:
510         min_size = fixed_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
511         data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
512         break;
513     default:
514         FIXME( "Information class %d not implemented\n", info_class );
515         return STATUS_INVALID_PARAMETER;
516     }
517
518     SERVER_START_REQ( get_key_value )
519     {
520         req->hkey = wine_server_obj_handle( handle );
521         wine_server_add_data( req, name->Buffer, name->Length );
522         if (length > fixed_size && data_ptr) wine_server_set_reply( req, data_ptr, length - fixed_size );
523         if (!(ret = wine_server_call( req )))
524         {
525             copy_key_value_info( info_class, info, length, reply->type,
526                                  name->Length, reply->total );
527             *result_len = fixed_size + (info_class == KeyValueBasicInformation ? 0 : reply->total);
528             if (length < min_size) ret = STATUS_BUFFER_TOO_SMALL;
529             else if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
530         }
531     }
532     SERVER_END_REQ;
533     return ret;
534 }
535
536 /******************************************************************************
537  * RtlpNtQueryValueKey [NTDLL.@]
538  *
539  */
540 NTSTATUS WINAPI RtlpNtQueryValueKey( HANDLE handle, ULONG *result_type, PBYTE dest,
541                                      DWORD *result_len, void *unknown )
542 {
543     KEY_VALUE_PARTIAL_INFORMATION *info;
544     UNICODE_STRING name;
545     NTSTATUS ret;
546     DWORD dwResultLen;
547     DWORD dwLen = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + (result_len ? *result_len : 0);
548
549     info = RtlAllocateHeap( GetProcessHeap(), 0, dwLen );
550     if (!info)
551       return STATUS_NO_MEMORY;
552
553     name.Length = 0;
554     ret = NtQueryValueKey( handle, &name, KeyValuePartialInformation, info, dwLen, &dwResultLen );
555
556     if (!ret || ret == STATUS_BUFFER_OVERFLOW)
557     {
558         if (result_len)
559             *result_len = info->DataLength;
560
561         if (result_type)
562             *result_type = info->Type;
563
564         if (ret != STATUS_BUFFER_OVERFLOW)
565             memcpy( dest, info->Data, info->DataLength );
566     }
567
568     RtlFreeHeap( GetProcessHeap(), 0, info );
569     return ret;
570 }
571
572 /******************************************************************************
573  *  NtFlushKey  [NTDLL.@]
574  *  ZwFlushKey  [NTDLL.@]
575  */
576 NTSTATUS WINAPI NtFlushKey(HANDLE key)
577 {
578     NTSTATUS ret;
579
580     TRACE("key=%p\n", key);
581
582     SERVER_START_REQ( flush_key )
583     {
584         req->hkey = wine_server_obj_handle( key );
585         ret = wine_server_call( req );
586     }
587     SERVER_END_REQ;
588     
589     return ret;
590 }
591
592 /******************************************************************************
593  *  NtLoadKey   [NTDLL.@]
594  *  ZwLoadKey   [NTDLL.@]
595  */
596 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file )
597 {
598     NTSTATUS ret;
599     HANDLE hive;
600     IO_STATUS_BLOCK io;
601
602     TRACE("(%p,%p)\n", attr, file);
603
604     ret = NtCreateFile(&hive, GENERIC_READ, file, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
605                        FILE_OPEN, 0, NULL, 0);
606     if (ret) return ret;
607
608     SERVER_START_REQ( load_registry )
609     {
610         req->hkey = wine_server_obj_handle( attr->RootDirectory );
611         req->file = wine_server_obj_handle( hive );
612         wine_server_add_data(req, attr->ObjectName->Buffer, attr->ObjectName->Length);
613         ret = wine_server_call( req );
614     }
615     SERVER_END_REQ;
616
617     NtClose(hive);
618    
619     return ret;
620 }
621
622 /******************************************************************************
623  *  NtNotifyChangeKey   [NTDLL.@]
624  *  ZwNotifyChangeKey   [NTDLL.@]
625  */
626 NTSTATUS WINAPI NtNotifyChangeKey(
627         IN HANDLE KeyHandle,
628         IN HANDLE Event,
629         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
630         IN PVOID ApcContext OPTIONAL,
631         OUT PIO_STATUS_BLOCK IoStatusBlock,
632         IN ULONG CompletionFilter,
633         IN BOOLEAN Asynchronous,
634         OUT PVOID ChangeBuffer,
635         IN ULONG Length,
636         IN BOOLEAN WatchSubtree)
637 {
638     NTSTATUS ret;
639
640     TRACE("(%p,%p,%p,%p,%p,0x%08x, 0x%08x,%p,0x%08x,0x%08x)\n",
641         KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
642         Asynchronous, ChangeBuffer, Length, WatchSubtree);
643
644     if (ApcRoutine || ApcContext || ChangeBuffer || Length)
645         FIXME("Unimplemented optional parameter\n");
646
647     if (!Asynchronous)
648     {
649         OBJECT_ATTRIBUTES attr;
650         InitializeObjectAttributes( &attr, NULL, 0, NULL, NULL );
651         ret = NtCreateEvent( &Event, EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE );
652         if (ret != STATUS_SUCCESS)
653             return ret;
654     }
655
656     SERVER_START_REQ( set_registry_notification )
657     {
658         req->hkey    = wine_server_obj_handle( KeyHandle );
659         req->event   = wine_server_obj_handle( Event );
660         req->subtree = WatchSubtree;
661         req->filter  = CompletionFilter;
662         ret = wine_server_call( req );
663     }
664     SERVER_END_REQ;
665  
666     if (!Asynchronous)
667     {
668         if (ret == STATUS_SUCCESS)
669             NtWaitForSingleObject( Event, FALSE, NULL );
670         NtClose( Event );
671     }
672
673     return STATUS_SUCCESS;
674 }
675
676 /******************************************************************************
677  * NtQueryMultipleValueKey [NTDLL]
678  * ZwQueryMultipleValueKey
679  */
680
681 NTSTATUS WINAPI NtQueryMultipleValueKey(
682         HANDLE KeyHandle,
683         PKEY_MULTIPLE_VALUE_INFORMATION ListOfValuesToQuery,
684         ULONG NumberOfItems,
685         PVOID MultipleValueInformation,
686         ULONG Length,
687         PULONG  ReturnLength)
688 {
689         FIXME("(%p,%p,0x%08x,%p,0x%08x,%p) stub!\n",
690         KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
691         Length,ReturnLength);
692         return STATUS_SUCCESS;
693 }
694
695 /******************************************************************************
696  * NtReplaceKey [NTDLL.@]
697  * ZwReplaceKey [NTDLL.@]
698  */
699 NTSTATUS WINAPI NtReplaceKey(
700         IN POBJECT_ATTRIBUTES ObjectAttributes,
701         IN HANDLE Key,
702         IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
703 {
704     FIXME("(%s,%p,%s),stub!\n", debugstr_ObjectAttributes(ObjectAttributes), Key,
705           debugstr_ObjectAttributes(ReplacedObjectAttributes) );
706     return STATUS_SUCCESS;
707 }
708 /******************************************************************************
709  * NtRestoreKey [NTDLL.@]
710  * ZwRestoreKey [NTDLL.@]
711  */
712 NTSTATUS WINAPI NtRestoreKey(
713         HANDLE KeyHandle,
714         HANDLE FileHandle,
715         ULONG RestoreFlags)
716 {
717         FIXME("(%p,%p,0x%08x) stub\n",
718         KeyHandle, FileHandle, RestoreFlags);
719         return STATUS_SUCCESS;
720 }
721 /******************************************************************************
722  * NtSaveKey [NTDLL.@]
723  * ZwSaveKey [NTDLL.@]
724  */
725 NTSTATUS WINAPI NtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle)
726 {
727     NTSTATUS ret;
728
729     TRACE("(%p,%p)\n", KeyHandle, FileHandle);
730
731     SERVER_START_REQ( save_registry )
732     {
733         req->hkey = wine_server_obj_handle( KeyHandle );
734         req->file = wine_server_obj_handle( FileHandle );
735         ret = wine_server_call( req );
736     }
737     SERVER_END_REQ;
738
739     return ret;
740 }
741 /******************************************************************************
742  * NtSetInformationKey [NTDLL.@]
743  * ZwSetInformationKey [NTDLL.@]
744  */
745 NTSTATUS WINAPI NtSetInformationKey(
746         IN HANDLE KeyHandle,
747         IN const int KeyInformationClass,
748         IN PVOID KeyInformation,
749         IN ULONG KeyInformationLength)
750 {
751         FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
752         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
753         return STATUS_SUCCESS;
754 }
755
756
757 /******************************************************************************
758  * NtSetValueKey [NTDLL.@]
759  * ZwSetValueKey [NTDLL.@]
760  *
761  * NOTES
762  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
763  *   NT does definitely care (aj)
764  */
765 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
766                                ULONG type, const void *data, ULONG count )
767 {
768     NTSTATUS ret;
769
770     TRACE( "(%p,%s,%d,%p,%d)\n", hkey, debugstr_us(name), type, data, count );
771
772     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
773
774     SERVER_START_REQ( set_key_value )
775     {
776         req->hkey    = wine_server_obj_handle( hkey );
777         req->type    = type;
778         req->namelen = name->Length;
779         wine_server_add_data( req, name->Buffer, name->Length );
780         wine_server_add_data( req, data, count );
781         ret = wine_server_call( req );
782     }
783     SERVER_END_REQ;
784     return ret;
785 }
786
787 /******************************************************************************
788  * RtlpNtSetValueKey [NTDLL.@]
789  *
790  */
791 NTSTATUS WINAPI RtlpNtSetValueKey( HANDLE hkey, ULONG type, const void *data,
792                                    ULONG count )
793 {
794     UNICODE_STRING name;
795
796     name.Length = 0;
797     return NtSetValueKey( hkey, &name, 0, type, data, count );
798 }
799
800 /******************************************************************************
801  * NtUnloadKey [NTDLL.@]
802  * ZwUnloadKey [NTDLL.@]
803  */
804 NTSTATUS WINAPI NtUnloadKey(IN POBJECT_ATTRIBUTES attr)
805 {
806     NTSTATUS ret;
807
808     TRACE("(%p)\n", attr);
809
810     SERVER_START_REQ( unload_registry )
811     {
812         req->hkey = wine_server_obj_handle( attr->RootDirectory );
813         ret = wine_server_call(req);
814     }
815     SERVER_END_REQ;
816
817     return ret;
818 }
819
820 /******************************************************************************
821  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
822  *
823  */
824 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath( IN OUT PUNICODE_STRING KeyPath)
825 {
826     static const WCHAR pathW[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\'};
827     HANDLE token;
828     NTSTATUS status;
829
830     status = NtOpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &token);
831     if (status == STATUS_NO_TOKEN)
832         status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token);
833     if (status == STATUS_SUCCESS)
834     {
835         char buffer[sizeof(TOKEN_USER) + sizeof(SID) + sizeof(DWORD)*SID_MAX_SUB_AUTHORITIES];
836         DWORD len = sizeof(buffer);
837
838         status = NtQueryInformationToken(token, TokenUser, buffer, len, &len);
839         if (status == STATUS_SUCCESS)
840         {
841             KeyPath->MaximumLength = 0;
842             status = RtlConvertSidToUnicodeString(KeyPath, ((TOKEN_USER *)buffer)->User.Sid, FALSE);
843             if (status == STATUS_BUFFER_OVERFLOW)
844             {
845                 PWCHAR buf = RtlAllocateHeap(GetProcessHeap(), 0,
846                                              sizeof(pathW) + KeyPath->Length + sizeof(WCHAR));
847                 if (buf)
848                 {
849                     memcpy(buf, pathW, sizeof(pathW));
850                     KeyPath->MaximumLength = KeyPath->Length + sizeof(WCHAR);
851                     KeyPath->Buffer = (PWCHAR)((LPBYTE)buf + sizeof(pathW));
852                     status = RtlConvertSidToUnicodeString(KeyPath,
853                                                           ((TOKEN_USER *)buffer)->User.Sid, FALSE);
854                     KeyPath->Buffer = buf;
855                     KeyPath->Length += sizeof(pathW);
856                     KeyPath->MaximumLength += sizeof(pathW);
857                 }
858                 else
859                     status = STATUS_NO_MEMORY;
860             }
861         }
862         NtClose(token);
863     }
864     return status;
865 }
866
867 /******************************************************************************
868  *  RtlOpenCurrentUser          [NTDLL.@]
869  *
870  * NOTES
871  *  If we return just HKEY_CURRENT_USER the advapi tries to find a remote
872  *  registry (odd handle) and fails.
873  */
874 NTSTATUS WINAPI RtlOpenCurrentUser(
875         IN ACCESS_MASK DesiredAccess, /* [in] */
876         OUT PHANDLE KeyHandle)        /* [out] handle of HKEY_CURRENT_USER */
877 {
878         OBJECT_ATTRIBUTES ObjectAttributes;
879         UNICODE_STRING ObjectName;
880         NTSTATUS ret;
881
882         TRACE("(0x%08x, %p)\n",DesiredAccess, KeyHandle);
883
884         if ((ret = RtlFormatCurrentUserKeyPath(&ObjectName))) return ret;
885         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
886         ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
887         RtlFreeUnicodeString(&ObjectName);
888         return ret;
889 }
890
891
892 static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
893                                         PRTL_QUERY_REGISTRY_TABLE pQuery, PVOID pContext, PVOID pEnvironment)
894 {
895     PUNICODE_STRING str;
896     UNICODE_STRING src, dst;
897     LONG *bin;
898     ULONG offset;
899     PWSTR wstr;
900     DWORD res;
901     NTSTATUS status = STATUS_SUCCESS;
902     ULONG len;
903     LPWSTR String;
904     ULONG count = 0;
905
906     if (pInfo == NULL)
907     {
908         if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
909             return STATUS_INVALID_PARAMETER;
910         else
911         {
912             status = pQuery->QueryRoutine(pQuery->Name, pQuery->DefaultType, pQuery->DefaultData,
913                                           pQuery->DefaultLength, pContext, pQuery->EntryContext);
914         }
915         return status;
916     }
917     len = pInfo->DataLength;
918
919     if (pQuery->Flags & RTL_QUERY_REGISTRY_DIRECT)
920     {
921         str = pQuery->EntryContext;
922
923         switch(pInfo->Type)
924         {
925         case REG_EXPAND_SZ:
926             if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
927             {
928                 RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
929                 res = 0;
930                 dst.MaximumLength = 0;
931                 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
932                 dst.Length = 0;
933                 dst.MaximumLength = res;
934                 dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
935                 RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
936                 status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
937                                      dst.Length, pContext, pQuery->EntryContext);
938                 RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
939             }
940
941         case REG_SZ:
942         case REG_LINK:
943             if (str->Buffer == NULL)
944                 RtlCreateUnicodeString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
945             else
946                 RtlAppendUnicodeToString(str, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
947             break;
948
949         case REG_MULTI_SZ:
950             if (!(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
951                 return STATUS_INVALID_PARAMETER;
952
953             if (str->Buffer == NULL)
954             {
955                 str->Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
956                 str->MaximumLength = len;
957             }
958             len = min(len, str->MaximumLength);
959             memcpy(str->Buffer, ((CHAR*)pInfo) + pInfo->DataOffset, len);
960             str->Length = len;
961             break;
962
963         default:
964             bin = pQuery->EntryContext;
965             if (pInfo->DataLength <= sizeof(ULONG))
966                 memcpy(bin, ((CHAR*)pInfo) + pInfo->DataOffset,
967                     pInfo->DataLength);
968             else
969             {
970                 if (bin[0] <= sizeof(ULONG))
971                 {
972                     memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
973                     min(-bin[0], pInfo->DataLength));
974                 }
975                 else
976                 {
977                    len = min(bin[0], pInfo->DataLength);
978                     bin[1] = len;
979                     bin[2] = pInfo->Type;
980                     memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
981                 }
982            }
983            break;
984         }
985     }
986     else
987     {
988         if((pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND) ||
989            (pInfo->Type != REG_EXPAND_SZ && pInfo->Type != REG_MULTI_SZ))
990         {
991             status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type,
992                 ((CHAR*)pInfo) + pInfo->DataOffset, pInfo->DataLength,
993                 pContext, pQuery->EntryContext);
994         }
995         else if (pInfo->Type == REG_EXPAND_SZ)
996         {
997             RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
998             res = 0;
999             dst.MaximumLength = 0;
1000             RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1001             dst.Length = 0;
1002             dst.MaximumLength = res;
1003             dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1004             RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1005             status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1006                                           dst.Length, pContext, pQuery->EntryContext);
1007             RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1008         }
1009         else /* REG_MULTI_SZ */
1010         {
1011             if(pQuery->Flags & RTL_QUERY_REGISTRY_NOEXPAND)
1012             {
1013                 for (offset = 0; offset <= pInfo->DataLength; offset += len + sizeof(WCHAR))
1014                     {
1015                     wstr = (WCHAR*)(((CHAR*)pInfo) + offset);
1016                     len = strlenW(wstr) * sizeof(WCHAR);
1017                     status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, wstr, len,
1018                         pContext, pQuery->EntryContext);
1019                     if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1020                         return status;
1021                     }
1022             }
1023             else
1024             {
1025                 while(count<=pInfo->DataLength)
1026                 {
1027                     String = (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset)+count;
1028                     count+=strlenW(String)+1;
1029                     RtlInitUnicodeString(&src, (WCHAR*)(((CHAR*)pInfo) + pInfo->DataOffset));
1030                     res = 0;
1031                     dst.MaximumLength = 0;
1032                     RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1033                     dst.Length = 0;
1034                     dst.MaximumLength = res;
1035                     dst.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, res * sizeof(WCHAR));
1036                     RtlExpandEnvironmentStrings_U(pEnvironment, &src, &dst, &res);
1037                     status = pQuery->QueryRoutine(pQuery->Name, pInfo->Type, dst.Buffer,
1038                                                   dst.Length, pContext, pQuery->EntryContext);
1039                     RtlFreeHeap(GetProcessHeap(), 0, dst.Buffer);
1040                     if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1041                         return status;
1042                 }
1043             }
1044         }
1045     }
1046     return status;
1047 }
1048
1049
1050 static NTSTATUS RTL_GetKeyHandle(ULONG RelativeTo, PCWSTR Path, PHANDLE handle)
1051 {
1052     UNICODE_STRING KeyString;
1053     OBJECT_ATTRIBUTES regkey;
1054     PCWSTR base;
1055     INT len;
1056     NTSTATUS status;
1057
1058     static const WCHAR empty[] = {0};
1059     static const WCHAR control[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
1060     '\\','S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1061     'C','o','n','t','r','o','l','\\',0};
1062
1063     static const WCHAR devicemap[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1064     'H','a','r','d','w','a','r','e','\\','D','e','v','i','c','e','M','a','p','\\',0};
1065
1066     static const WCHAR services[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1067     'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1068     'S','e','r','v','i','c','e','s','\\',0};
1069
1070     static const WCHAR user[] = {'\\','R','e','g','i','s','t','r','y','\\','U','s','e','r','\\',
1071     'C','u','r','r','e','n','t','U','s','e','r','\\',0};
1072
1073     static const WCHAR windows_nt[] = {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\',
1074     'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1075     'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',0};
1076
1077     switch (RelativeTo & 0xff)
1078     {
1079     case RTL_REGISTRY_ABSOLUTE:
1080         base = empty;
1081         break;
1082
1083     case RTL_REGISTRY_CONTROL:
1084         base = control;
1085         break;
1086
1087     case RTL_REGISTRY_DEVICEMAP:
1088         base = devicemap;
1089         break;
1090
1091     case RTL_REGISTRY_SERVICES:
1092         base = services;
1093         break;
1094
1095     case RTL_REGISTRY_USER:
1096         base = user;
1097         break;
1098
1099     case RTL_REGISTRY_WINDOWS_NT:
1100         base = windows_nt;
1101         break;
1102
1103     default:
1104         return STATUS_INVALID_PARAMETER;
1105     }
1106
1107     len = (strlenW(base) + strlenW(Path) + 1) * sizeof(WCHAR);
1108     KeyString.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, len);
1109     if (KeyString.Buffer == NULL)
1110         return STATUS_NO_MEMORY;
1111
1112     strcpyW(KeyString.Buffer, base);
1113     strcatW(KeyString.Buffer, Path);
1114     KeyString.Length = len - sizeof(WCHAR);
1115     KeyString.MaximumLength = len;
1116     InitializeObjectAttributes(&regkey, &KeyString, OBJ_CASE_INSENSITIVE, NULL, NULL);
1117     status = NtOpenKey(handle, KEY_ALL_ACCESS, &regkey);
1118     RtlFreeHeap(GetProcessHeap(), 0, KeyString.Buffer);
1119     return status;
1120 }
1121
1122 /*************************************************************************
1123  * RtlQueryRegistryValues   [NTDLL.@]
1124  *
1125  * Query multiple registry values with a signle call.
1126  *
1127  * PARAMS
1128  *  RelativeTo  [I] Registry path that Path refers to
1129  *  Path        [I] Path to key
1130  *  QueryTable  [I] Table of key values to query
1131  *  Context     [I] Parameter to pass to the application defined QueryRoutine function
1132  *  Environment [I] Optional parameter to use when performing expansion
1133  *
1134  * RETURNS
1135  *  STATUS_SUCCESS or an appropriate NTSTATUS error code.
1136  */
1137 NTSTATUS WINAPI RtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path,
1138                                        IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context,
1139                                        IN PVOID Environment OPTIONAL)
1140 {
1141     UNICODE_STRING Value;
1142     HANDLE handle, topkey;
1143     PKEY_VALUE_FULL_INFORMATION pInfo = NULL;
1144     ULONG len, buflen = 0;
1145     NTSTATUS status=STATUS_SUCCESS, ret = STATUS_SUCCESS;
1146     INT i;
1147
1148     TRACE("(%d, %s, %p, %p, %p)\n", RelativeTo, debugstr_w(Path), QueryTable, Context, Environment);
1149
1150     if(Path == NULL)
1151         return STATUS_INVALID_PARAMETER;
1152
1153     /* get a valid handle */
1154     if (RelativeTo & RTL_REGISTRY_HANDLE)
1155         topkey = handle = (HANDLE)Path;
1156     else
1157     {
1158         status = RTL_GetKeyHandle(RelativeTo, Path, &topkey);
1159         handle = topkey;
1160     }
1161     if(status != STATUS_SUCCESS)
1162         return status;
1163
1164     /* Process query table entries */
1165     for (; QueryTable->QueryRoutine != NULL || QueryTable->Name != NULL; ++QueryTable)
1166     {
1167         if (QueryTable->Flags &
1168             (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY))
1169         {
1170             /* topkey must be kept open just in case we will reuse it later */
1171             if (handle != topkey)
1172                 NtClose(handle);
1173
1174             if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY)
1175             {
1176                 handle = 0;
1177                 status = RTL_GetKeyHandle(PtrToUlong(QueryTable->Name), Path, &handle);
1178                 if(status != STATUS_SUCCESS)
1179                 {
1180                     ret = status;
1181                     goto out;
1182                 }
1183             }
1184             else
1185                 handle = topkey;
1186         }
1187
1188         if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE)
1189         {
1190             QueryTable->QueryRoutine(QueryTable->Name, REG_NONE, NULL, 0,
1191                 Context, QueryTable->EntryContext);
1192             continue;
1193         }
1194
1195         if (!handle)
1196         {
1197             if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1198             {
1199                 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1200                 goto out;
1201             }
1202             continue;
1203         }
1204
1205         if (QueryTable->Name == NULL)
1206         {
1207             if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)
1208             {
1209                 ret = STATUS_INVALID_PARAMETER;
1210                 goto out;
1211             }
1212
1213             /* Report all subkeys */
1214             for (i = 0;; ++i)
1215             {
1216                 status = NtEnumerateValueKey(handle, i,
1217                     KeyValueFullInformation, pInfo, buflen, &len);
1218                 if (status == STATUS_NO_MORE_ENTRIES)
1219                     break;
1220                 if (status == STATUS_BUFFER_OVERFLOW ||
1221                     status == STATUS_BUFFER_TOO_SMALL)
1222                 {
1223                     buflen = len;
1224                     RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1225                     pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1226                     NtEnumerateValueKey(handle, i, KeyValueFullInformation,
1227                         pInfo, buflen, &len);
1228                 }
1229
1230                 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1231                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1232                 {
1233                     ret = status;
1234                     goto out;
1235                 }
1236                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1237                 {
1238                     RtlInitUnicodeString(&Value, pInfo->Name);
1239                     NtDeleteValueKey(handle, &Value);
1240                 }
1241             }
1242
1243             if (i == 0  && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED))
1244             {
1245                 ret = STATUS_OBJECT_NAME_NOT_FOUND;
1246                 goto out;
1247             }
1248         }
1249         else
1250         {
1251             RtlInitUnicodeString(&Value, QueryTable->Name);
1252             status = NtQueryValueKey(handle, &Value, KeyValueFullInformation,
1253                 pInfo, buflen, &len);
1254             if (status == STATUS_BUFFER_OVERFLOW ||
1255                 status == STATUS_BUFFER_TOO_SMALL)
1256             {
1257                 buflen = len;
1258                 RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1259                 pInfo = RtlAllocateHeap(GetProcessHeap(), 0, buflen);
1260                 status = NtQueryValueKey(handle, &Value,
1261                     KeyValueFullInformation, pInfo, buflen, &len);
1262             }
1263             if (status != STATUS_SUCCESS)
1264             {
1265                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)
1266                 {
1267                     ret = STATUS_OBJECT_NAME_NOT_FOUND;
1268                     goto out;
1269                 }
1270                 status = RTL_ReportRegistryValue(NULL, QueryTable, Context, Environment);
1271                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1272                 {
1273                     ret = status;
1274                     goto out;
1275                 }
1276             }
1277             else
1278             {
1279                 status = RTL_ReportRegistryValue(pInfo, QueryTable, Context, Environment);
1280                 if(status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
1281                 {
1282                     ret = status;
1283                     goto out;
1284                 }
1285                 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)
1286                     NtDeleteValueKey(handle, &Value);
1287             }
1288         }
1289     }
1290
1291 out:
1292     RtlFreeHeap(GetProcessHeap(), 0, pInfo);
1293     if (handle != topkey)
1294         NtClose(handle);
1295     NtClose(topkey);
1296     return ret;
1297 }
1298
1299 /*************************************************************************
1300  * RtlCheckRegistryKey   [NTDLL.@]
1301  *
1302  * Query multiple registry values with a signle call.
1303  *
1304  * PARAMS
1305  *  RelativeTo [I] Registry path that Path refers to
1306  *  Path       [I] Path to key
1307  *
1308  * RETURNS
1309  *  STATUS_SUCCESS if the specified key exists, or an NTSTATUS error code.
1310  */
1311 NTSTATUS WINAPI RtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path)
1312 {
1313     HANDLE handle;
1314     NTSTATUS status;
1315
1316     TRACE("(%d, %s)\n", RelativeTo, debugstr_w(Path));
1317
1318     if((!RelativeTo) && Path == NULL)
1319         return STATUS_OBJECT_PATH_SYNTAX_BAD;
1320     if(RelativeTo & RTL_REGISTRY_HANDLE)
1321         return STATUS_SUCCESS;
1322
1323     status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1324     if (handle) NtClose(handle);
1325     if (status == STATUS_INVALID_HANDLE) status = STATUS_OBJECT_NAME_NOT_FOUND;
1326     return status;
1327 }
1328
1329 /*************************************************************************
1330  * RtlDeleteRegistryValue   [NTDLL.@]
1331  *
1332  * Query multiple registry values with a signle call.
1333  *
1334  * PARAMS
1335  *  RelativeTo [I] Registry path that Path refers to
1336  *  Path       [I] Path to key
1337  *  ValueName  [I] Name of the value to delete
1338  *
1339  * RETURNS
1340  *  STATUS_SUCCESS if the specified key is successfully deleted, or an NTSTATUS error code.
1341  */
1342 NTSTATUS WINAPI RtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName)
1343 {
1344     NTSTATUS status;
1345     HANDLE handle;
1346     UNICODE_STRING Value;
1347
1348     TRACE("(%d, %s, %s)\n", RelativeTo, debugstr_w(Path), debugstr_w(ValueName));
1349
1350     RtlInitUnicodeString(&Value, ValueName);
1351     if(RelativeTo == RTL_REGISTRY_HANDLE)
1352     {
1353         return NtDeleteValueKey((HANDLE)Path, &Value);
1354     }
1355     status = RTL_GetKeyHandle(RelativeTo, Path, &handle);
1356     if (status) return status;
1357     status = NtDeleteValueKey(handle, &Value);
1358     NtClose(handle);
1359     return status;
1360 }
1361
1362 /*************************************************************************
1363  * RtlWriteRegistryValue   [NTDLL.@]
1364  *
1365  * Sets the registry value with provided data.
1366  *
1367  * PARAMS
1368  *  RelativeTo [I] Registry path that path parameter refers to
1369  *  path       [I] Path to the key (or handle - see RTL_GetKeyHandle)
1370  *  name       [I] Name of the registry value to set
1371  *  type       [I] Type of the registry key to set
1372  *  data       [I] Pointer to the user data to be set
1373  *  length     [I] Length of the user data pointed by data
1374  *
1375  * RETURNS
1376  *  STATUS_SUCCESS if the specified key is successfully set,
1377  *  or an NTSTATUS error code.
1378  */
1379 NTSTATUS WINAPI RtlWriteRegistryValue( ULONG RelativeTo, PCWSTR path, PCWSTR name,
1380                                        ULONG type, PVOID data, ULONG length )
1381 {
1382     HANDLE hkey;
1383     NTSTATUS status;
1384     UNICODE_STRING str;
1385
1386     TRACE( "(%d, %s, %s) -> %d: %p [%d]\n", RelativeTo, debugstr_w(path), debugstr_w(name),
1387            type, data, length );
1388
1389     RtlInitUnicodeString( &str, name );
1390
1391     if (RelativeTo == RTL_REGISTRY_HANDLE)
1392         return NtSetValueKey( (HANDLE)path, &str, 0, type, data, length );
1393
1394     status = RTL_GetKeyHandle( RelativeTo, path, &hkey );
1395     if (status != STATUS_SUCCESS) return status;
1396
1397     status = NtSetValueKey( hkey, &str, 0, type, data, length );
1398     NtClose( hkey );
1399
1400     return status;
1401 }