Added include protection for unistd.h and sys/time.h.
[wine] / memory / registry.c
1 /*
2  * Registry management
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
6  * Based on misc/registry.c code
7  * Copyright (C) 1996 Marcus Meissner
8  * Copyright (C) 1998 Matthew Becker
9  * Copyright (C) 1999 Sylvain St-Germain
10  *
11  * This file is concerned about handle management and interaction with the Wine server.
12  * Registry file I/O is in misc/registry.c.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28
29 #include "config.h"
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "winerror.h"
40 #include "wine/winbase16.h"
41 #include "wine/unicode.h"
42 #include "wine/server.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
46
47
48 /* check if value type needs string conversion (Ansi<->Unicode) */
49 static inline int is_string( DWORD type )
50 {
51     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
52 }
53
54
55 /******************************************************************************
56  *           RegCreateKeyExA   [ADVAPI32.@]
57  */
58 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
59                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
60                               LPHKEY retkey, LPDWORD dispos )
61 {
62     OBJECT_ATTRIBUTES attr;
63     UNICODE_STRING nameW, classW;
64     ANSI_STRING nameA, classA;
65     NTSTATUS status;
66
67     if (reserved) return ERROR_INVALID_PARAMETER;
68     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
69
70     attr.Length = sizeof(attr);
71     attr.RootDirectory = hkey;
72     attr.ObjectName = &nameW;
73     attr.Attributes = 0;
74     attr.SecurityDescriptor = NULL;
75     attr.SecurityQualityOfService = NULL;
76     RtlInitAnsiString( &nameA, name );
77     RtlInitAnsiString( &classA, class );
78
79     /* FIXME: should use Unicode buffer in TEB */
80     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
81     {
82         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
83         {
84             status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
85             RtlFreeUnicodeString( &classW );
86         }
87         RtlFreeUnicodeString( &nameW );
88     }
89     return RtlNtStatusToDosError( status );
90 }
91
92
93 /******************************************************************************
94  *           RegCreateKeyA   [ADVAPI32.@]
95  */
96 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
97 {
98     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
99                             KEY_ALL_ACCESS, NULL, retkey, NULL );
100 }
101
102
103
104 /******************************************************************************
105  *           RegOpenKeyExA   [ADVAPI32.@]
106  */
107 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
108 {
109     OBJECT_ATTRIBUTES attr;
110     UNICODE_STRING nameW;
111     STRING nameA;
112     NTSTATUS status;
113
114     attr.Length = sizeof(attr);
115     attr.RootDirectory = hkey;
116     attr.ObjectName = &nameW;
117     attr.Attributes = 0;
118     attr.SecurityDescriptor = NULL;
119     attr.SecurityQualityOfService = NULL;
120
121     RtlInitAnsiString( &nameA, name );
122     /* FIXME: should use Unicode buffer in TEB */
123     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
124     {
125         status = NtOpenKey( retkey, access, &attr );
126         RtlFreeUnicodeString( &nameW );
127     }
128     return RtlNtStatusToDosError( status );
129 }
130
131
132 /******************************************************************************
133  *           RegOpenKeyA   [ADVAPI32.@]
134  */
135 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
136 {
137     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
138 }
139
140
141 /******************************************************************************
142  *           RegEnumKeyExA   [ADVAPI32.@]
143  */
144 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
145                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
146 {
147     NTSTATUS status;
148     char buffer[256], *buf_ptr = buffer;
149     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
150     DWORD total_size;
151
152     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
153            name_len ? *name_len : -1, reserved, class, class_len, ft );
154
155     if (reserved) return ERROR_INVALID_PARAMETER;
156
157     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
158                              buffer, sizeof(buffer), &total_size );
159
160     while (status == STATUS_BUFFER_OVERFLOW)
161     {
162         /* retry with a dynamically allocated buffer */
163         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
164         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
165             return ERROR_NOT_ENOUGH_MEMORY;
166         info = (KEY_NODE_INFORMATION *)buf_ptr;
167         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
168                                  buf_ptr, total_size, &total_size );
169     }
170
171     if (!status)
172     {
173         DWORD len, cls_len;
174
175         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
176         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
177                                    info->ClassLength );
178         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
179
180         if (len >= *name_len || (class_len && (cls_len >= *class_len)))
181             status = STATUS_BUFFER_OVERFLOW;
182         else
183         {
184             *name_len = len;
185             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
186             name[len] = 0;
187             if (class_len)
188             {
189                 *class_len = cls_len;
190                 if (class)
191                 {
192                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
193                                             (WCHAR *)(buf_ptr + info->ClassOffset),
194                                             info->ClassLength );
195                     class[cls_len] = 0;
196                 }
197             }
198         }
199     }
200
201     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
202     return RtlNtStatusToDosError( status );
203 }
204
205
206 /******************************************************************************
207  *           RegEnumKeyA   [ADVAPI32.@]
208  */
209 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
210 {
211     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
212 }
213
214
215 /******************************************************************************
216  *           RegQueryInfoKeyA   [ADVAPI32.@]
217  */
218 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
219                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
220                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
221                                LPDWORD security, FILETIME *modif )
222 {
223     NTSTATUS status;
224     char buffer[256], *buf_ptr = buffer;
225     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
226     DWORD total_size, len;
227
228     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
229            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
230
231     if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
232         return ERROR_INVALID_PARAMETER;
233
234     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
235     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
236
237     if (class || class_len)
238     {
239         /* retry with a dynamically allocated buffer */
240         while (status == STATUS_BUFFER_OVERFLOW)
241         {
242             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
243             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
244                 return ERROR_NOT_ENOUGH_MEMORY;
245             info = (KEY_FULL_INFORMATION *)buf_ptr;
246             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
247         }
248
249         if (status) goto done;
250
251         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
252         if (class_len)
253         {
254             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
255             *class_len = len;
256         }
257         if (class && !status)
258         {
259             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
260                                     info->ClassLength );
261             class[len] = 0;
262         }
263     }
264     else status = STATUS_SUCCESS;
265
266     if (subkeys) *subkeys = info->SubKeys;
267     if (max_subkey) *max_subkey = info->MaxNameLen;
268     if (max_class) *max_class = info->MaxClassLen;
269     if (values) *values = info->Values;
270     if (max_value) *max_value = info->MaxValueNameLen;
271     if (max_data) *max_data = info->MaxValueDataLen;
272     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
273
274  done:
275     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
276     return RtlNtStatusToDosError( status );
277 }
278
279
280 /******************************************************************************
281  *           RegCloseKey   [ADVAPI32.@]
282  *
283  * Releases the handle of the specified key
284  *
285  * PARAMS
286  *    hkey [I] Handle of key to close
287  *
288  * RETURNS
289  *    Success: ERROR_SUCCESS
290  *    Failure: Error code
291  */
292 DWORD WINAPI RegCloseKey( HKEY hkey )
293 {
294     if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
295     return RtlNtStatusToDosError( NtClose( hkey ) );
296 }
297
298
299 /******************************************************************************
300  *           RegDeleteKeyA   [ADVAPI32.@]
301  */
302 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
303 {
304     DWORD ret;
305     HKEY tmp;
306
307     if (!name || !*name) return NtDeleteKey( hkey );
308     if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
309     {
310         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
311         RegCloseKey( tmp );
312     }
313     return ret;
314 }
315
316
317
318 /******************************************************************************
319  *           RegSetValueExA   [ADVAPI32.@]
320  */
321 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
322                              CONST BYTE *data, DWORD count )
323 {
324     UNICODE_STRING nameW;
325     ANSI_STRING nameA;
326     WCHAR *dataW = NULL;
327     NTSTATUS status;
328
329     if (count && is_string(type))
330     {
331         /* if user forgot to count terminating null, add it (yes NT does this) */
332         if (data[count-1] && !data[count]) count++;
333     }
334
335     if (is_string( type )) /* need to convert to Unicode */
336     {
337         DWORD lenW;
338         RtlMultiByteToUnicodeSize( &lenW, data, count );
339         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
340         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
341         count = lenW;
342         data = (BYTE *)dataW;
343     }
344
345     RtlInitAnsiString( &nameA, name );
346     /* FIXME: should use Unicode buffer in TEB */
347     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
348     {
349         status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
350         RtlFreeUnicodeString( &nameW );
351     }
352     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
353     return RtlNtStatusToDosError( status );
354 }
355
356
357 /******************************************************************************
358  *           RegSetValueA   [ADVAPI32.@]
359  */
360 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
361 {
362     HKEY subkey = hkey;
363     DWORD ret;
364
365     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
366
367     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
368
369     if (name && name[0])  /* need to create the subkey */
370     {
371         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
372     }
373     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
374     if (subkey != hkey) RegCloseKey( subkey );
375     return ret;
376 }
377
378
379
380 /******************************************************************************
381  *           RegQueryValueExA   [ADVAPI32.@]
382  *
383  * NOTES:
384  * the documentation is wrong: if the buffer is too small it remains untouched
385  */
386 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
387                                LPBYTE data, LPDWORD count )
388 {
389     NTSTATUS status;
390     ANSI_STRING nameA;
391     UNICODE_STRING nameW;
392     DWORD total_size;
393     char buffer[256], *buf_ptr = buffer;
394     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
395     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
396
397     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
398           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
399
400     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
401
402     RtlInitAnsiString( &nameA, name );
403     /* FIXME: should use Unicode buffer in TEB */
404     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
405         return RtlNtStatusToDosError(status);
406
407     status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
408                               buffer, sizeof(buffer), &total_size );
409     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
410
411     /* we need to fetch the contents for a string type even if not requested,
412      * because we need to compute the length of the ASCII string. */
413     if (data || is_string(info->Type))
414     {
415         /* retry with a dynamically allocated buffer */
416         while (status == STATUS_BUFFER_OVERFLOW)
417         {
418             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
419             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
420             {
421                 status = STATUS_NO_MEMORY;
422                 goto done;
423             }
424             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
425             status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
426                                       buf_ptr, total_size, &total_size );
427         }
428
429         if (!status)
430         {
431             if (is_string(info->Type))
432             {
433                 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
434                                                  (total_size - info_size) /sizeof(WCHAR),
435                                                  NULL, 0, NULL, NULL );
436                 if (data && len)
437                 {
438                     if (len > *count) status = STATUS_BUFFER_OVERFLOW;
439                     else
440                     {
441                         WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
442                                              (total_size - info_size) /sizeof(WCHAR),
443                                              data, len, NULL, NULL );
444                         /* if the type is REG_SZ and data is not 0-terminated
445                          * and there is enough space in the buffer NT appends a \0 */
446                         if (len < *count && data[len-1]) data[len] = 0;
447                     }
448                 }
449                 total_size = len + info_size;
450             }
451             else if (data)
452             {
453                 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
454                 else memcpy( data, buf_ptr + info_size, total_size - info_size );
455             }
456         }
457         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
458     }
459
460     if (type) *type = info->Type;
461     if (count) *count = total_size - info_size;
462
463  done:
464     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
465     RtlFreeUnicodeString( &nameW );
466     return RtlNtStatusToDosError(status);
467 }
468
469
470 /******************************************************************************
471  *           RegQueryValueA   [ADVAPI32.@]
472  */
473 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
474 {
475     DWORD ret;
476     HKEY subkey = hkey;
477
478     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
479
480     if (name && name[0])
481     {
482         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
483     }
484     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
485     if (subkey != hkey) RegCloseKey( subkey );
486     if (ret == ERROR_FILE_NOT_FOUND)
487     {
488         /* return empty string if default value not found */
489         if (data) *data = 0;
490         if (count) *count = 1;
491         ret = ERROR_SUCCESS;
492     }
493     return ret;
494 }
495
496
497 /******************************************************************************
498  *           RegEnumValueA   [ADVAPI32.@]
499  */
500 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
501                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
502 {
503     NTSTATUS status;
504     DWORD total_size;
505     char buffer[256], *buf_ptr = buffer;
506     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
507     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
508
509     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
510           hkey, index, value, val_count, reserved, type, data, count );
511
512     /* NT only checks count, not val_count */
513     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
514
515     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
516     if (data) total_size += *count;
517     total_size = min( sizeof(buffer), total_size );
518
519     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
520                                   buffer, total_size, &total_size );
521     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
522
523     /* we need to fetch the contents for a string type even if not requested,
524      * because we need to compute the length of the ASCII string. */
525     if (value || data || is_string(info->Type))
526     {
527         /* retry with a dynamically allocated buffer */
528         while (status == STATUS_BUFFER_OVERFLOW)
529         {
530             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
531             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
532                 return ERROR_NOT_ENOUGH_MEMORY;
533             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
534             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
535                                           buf_ptr, total_size, &total_size );
536         }
537
538         if (status) goto done;
539
540         if (is_string(info->Type))
541         {
542             DWORD len;
543             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
544                                        total_size - info->DataOffset );
545             if (data && len)
546             {
547                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
548                 else
549                 {
550                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
551                                             total_size - info->DataOffset );
552                     /* if the type is REG_SZ and data is not 0-terminated
553                      * and there is enough space in the buffer NT appends a \0 */
554                     if (len < *count && data[len-1]) data[len] = 0;
555                 }
556             }
557             info->DataLength = len;
558         }
559         else if (data)
560         {
561             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
562             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
563         }
564
565         if (value && !status)
566         {
567             DWORD len;
568
569             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
570             if (len >= *val_count)
571             {
572                 status = STATUS_BUFFER_OVERFLOW;
573                 if (*val_count)
574                 {
575                     len = *val_count - 1;
576                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
577                     value[len] = 0;
578                 }
579             }
580             else
581             {
582                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
583                 value[len] = 0;
584                 *val_count = len;
585             }
586         }
587     }
588     else status = STATUS_SUCCESS;
589
590     if (type) *type = info->Type;
591     if (count) *count = info->DataLength;
592
593  done:
594     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
595     return RtlNtStatusToDosError(status);
596 }
597
598
599
600 /******************************************************************************
601  *           RegDeleteValueA   [ADVAPI32.@]
602  */
603 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
604 {
605     UNICODE_STRING nameW;
606     STRING nameA;
607     NTSTATUS status;
608
609     RtlInitAnsiString( &nameA, name );
610     /* FIXME: should use Unicode buffer in TEB */
611     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
612     {
613         status = NtDeleteValueKey( hkey, &nameW );
614         RtlFreeUnicodeString( &nameW );
615     }
616     return RtlNtStatusToDosError( status );
617 }
618
619
620 /******************************************************************************
621  *           RegLoadKeyA   [ADVAPI32.@]
622  */
623 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
624 {
625     HANDLE file;
626     WCHAR buffer[MAX_PATH];
627     DWORD ret, len, err = GetLastError();
628
629     TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
630
631     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
632     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
633
634     if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
635         return ERROR_INVALID_PARAMETER;
636
637     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
638                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
639     {
640         ret = GetLastError();
641         goto done;
642     }
643
644     SERVER_START_REQ( load_registry )
645     {
646         req->hkey  = hkey;
647         req->file  = file;
648         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
649         ret = RtlNtStatusToDosError( wine_server_call(req) );
650     }
651     SERVER_END_REQ;
652     CloseHandle( file );
653
654  done:
655     SetLastError( err );  /* restore the last error code */
656     return ret;
657 }
658
659
660 /******************************************************************************
661  *           RegSaveKeyA   [ADVAPI32.@]
662  *
663  * PARAMS
664  *    hkey   [I] Handle of key where save begins
665  *    lpFile [I] Address of filename to save to
666  *    sa     [I] Address of security structure
667  */
668 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
669 {
670     char buffer[1024];
671     int count = 0;
672     LPSTR name;
673     DWORD ret, err;
674     HANDLE handle;
675
676     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
677
678     if (!file || !*file) return ERROR_INVALID_PARAMETER;
679
680     err = GetLastError();
681     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
682     for (;;)
683     {
684         sprintf( name, "reg%04x.tmp", count++ );
685         handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
686                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
687         if (handle != INVALID_HANDLE_VALUE) break;
688         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
689
690         /* Something gone haywire ? Please report if this happens abnormally */
691         if (count >= 100)
692             MESSAGE("Wow, we are already fiddling with a temp file %s with an ordinal as high as %d !\nYou might want to delete all corresponding temp files in that directory.\n", buffer, count);
693     }
694
695     SERVER_START_REQ( save_registry )
696     {
697         req->hkey = hkey;
698         req->file = handle;
699         ret = RtlNtStatusToDosError( wine_server_call( req ) );
700     }
701     SERVER_END_REQ;
702
703     CloseHandle( handle );
704     if (!ret)
705     {
706         if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
707         {
708             ERR( "Failed to move %s to %s\n", buffer, file );
709             ret = GetLastError();
710         }
711     }
712     if (ret) DeleteFileA( buffer );
713
714 done:
715     SetLastError( err );  /* restore last error code */
716     return ret;
717 }