implemented RegCopyTreeW() (untested!)
Modified: trunk/reactos/lib/advapi32/reg/reg.c

Modified: trunk/reactos/lib/advapi32/reg/reg.c
--- trunk/reactos/lib/advapi32/reg/reg.c	2005-09-24 13:19:25 UTC (rev 18025)
+++ trunk/reactos/lib/advapi32/reg/reg.c	2005-09-24 17:08:13 UTC (rev 18026)
@@ -319,10 +319,294 @@
 }
 
 
+static NTSTATUS
+RegpCopyTree(IN HKEY hKeySrc,
+             IN HKEY hKeyDest)
+{
+    typedef struct
+    {
+        LIST_ENTRY ListEntry;
+        HANDLE hKeySrc;
+        HANDLE hKeyDest;
+    } REGP_COPY_KEYS, *PREGP_COPY_KEYS;
+
+    LIST_ENTRY copyQueueHead;
+    PREGP_COPY_KEYS copyKeys, newCopyKeys;
+    union
+    {
+        KEY_VALUE_FULL_INFORMATION *KeyValue;
+        KEY_NODE_INFORMATION *KeyNode;
+        PVOID Buffer;
+    } Info;
+    ULONG Index, BufferSizeRequired, BufferSize = 0x200;
+    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status2 = STATUS_SUCCESS;
+    
+    InitializeListHead(&copyQueueHead);
+    
+    Info.Buffer = RtlAllocateHeap(ProcessHeap,
+                                  0,
+                                  BufferSize);
+    if (Info.Buffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    
+    copyKeys = RtlAllocateHeap(ProcessHeap,
+                               0,
+                               sizeof(REGP_COPY_KEYS));
+    if (copyKeys != NULL)
+    {
+        copyKeys->hKeySrc = hKeySrc;
+        copyKeys->hKeyDest = hKeyDest;
+        InsertHeadList(&copyQueueHead,
+                       &copyKeys->ListEntry);
+        
+        /* FIXME - copy security from hKeySrc to hKeyDest or just for the subkeys? */
+        
+        do
+        {
+            copyKeys = CONTAINING_RECORD(copyQueueHead.Flink,
+                                         REGP_COPY_KEYS,
+                                         ListEntry);
+
+            /* enumerate all values and copy them */
+            Index = 0;
+            for (;;)
+            {
+                Status2 = NtEnumerateValueKey(copyKeys->hKeySrc,
+                                              Index,
+                                              KeyValueFullInformation,
+                                              Info.KeyValue,
+                                              BufferSize,
+                                              &BufferSizeRequired);
+                if (NT_SUCCESS(Status2))
+                {
+                    UNICODE_STRING ValueName;
+                    PVOID Data;
+                    
+                    /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
+                    ValueName.Length = Info.KeyValue->NameLength;
+                    ValueName.MaximumLength = ValueName.Length;
+                    ValueName.Buffer = Info.KeyValue->Name;
+                    
+                    Data = (PVOID)((ULONG_PTR)Info.KeyValue + Info.KeyValue->DataOffset);
+                    
+                    Status2 = NtSetValueKey(copyKeys->hKeyDest,
+                                            &ValueName,
+                                            Info.KeyValue->TitleIndex,
+                                            Info.KeyValue->Type,
+                                            Data,
+                                            Info.KeyValue->DataLength);
+
+                    /* don't break, let's try to copy as many values as possible */
+                    if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
+                    {
+                        Status = Status2;
+                    }
+
+                    Index++;
+                }
+                else if (Status2 == STATUS_BUFFER_OVERFLOW)
+                {
+                    PVOID Buffer;
+
+                    ASSERT(BufferSize < BufferSizeRequired);
+
+                    Buffer = RtlReAllocateHeap(ProcessHeap,
+                                               0,
+                                               Info.Buffer,
+                                               BufferSizeRequired);
+                    if (Buffer != NULL)
+                    {
+                        Info.Buffer = Buffer;
+                        /* try again */
+                    }
+                    else
+                    {
+                        /* don't break, let's try to copy as many values as possible */
+                        Status2 = STATUS_INSUFFICIENT_RESOURCES;
+                        Index++;
+                        
+                        if (NT_SUCCESS(Status))
+                        {
+                            Status = Status2;
+                        }
+                    }
+                }
+                else
+                {
+                    /* break to avoid an infinite loop in case of denied access or
+                       other errors! */
+                    if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
+                    {
+                        Status = Status2;
+                    }
+                    
+                    break;
+                }
+            }
+            
+            /* enumerate all subkeys and open and enqueue them */
+            Index = 0;
+            for (;;)
+            {
+                Status2 = NtEnumerateKey(copyKeys->hKeySrc,
+                                         Index,
+                                         KeyNodeInformation,
+                                         Info.KeyNode,
+                                         BufferSize,
+                                         &BufferSizeRequired);
+                if (NT_SUCCESS(Status2))
+                {
+                    HANDLE KeyHandle, NewKeyHandle;
+                    OBJECT_ATTRIBUTES ObjectAttributes;
+                    UNICODE_STRING SubKeyName, ClassName;
+                    
+                    /* don't use RtlInitUnicodeString as the string is not NULL-terminated! */
+                    SubKeyName.Length = Info.KeyNode->NameLength;
+                    SubKeyName.MaximumLength = SubKeyName.Length;
+                    SubKeyName.Buffer = Info.KeyNode->Name;
+                    ClassName.Length = Info.KeyNode->ClassLength;
+                    ClassName.MaximumLength = ClassName.Length;
+                    ClassName.Buffer = (PWSTR)((ULONG_PTR)Info.KeyNode + Info.KeyNode->ClassOffset);
+                    
+                    /* open the subkey with sufficient rights */
+                    
+                    InitializeObjectAttributes(&ObjectAttributes,
+                                               &SubKeyName,
+                                               OBJ_CASE_INSENSITIVE,
+                                               copyKeys->hKeySrc,
+                                               NULL);
+                    
+                    Status2 = NtOpenKey(&KeyHandle,
+                                        KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                                        &ObjectAttributes);
+                    if (NT_SUCCESS(Status2))
+                    {
+                        /* FIXME - attempt to query the security information */
+                        
+                        InitializeObjectAttributes(&ObjectAttributes,
+                                               &SubKeyName,
+                                               OBJ_CASE_INSENSITIVE,
+                                               copyKeys->hKeyDest,
+                                               NULL);
+
+                        Status2 = NtCreateKey(&NewKeyHandle,
+                                              KEY_ALL_ACCESS,
+                                              &ObjectAttributes,
+                                              Info.KeyNode->TitleIndex,
+                                              &ClassName,
+                                              0,
+                                              NULL);
+                        if (NT_SUCCESS(Status2))
+                        {
+                            newCopyKeys = RtlAllocateHeap(ProcessHeap,
+                                                          0,
+                                                          sizeof(REGP_COPY_KEYS));
+                            if (newCopyKeys != NULL)
+                            {
+                                /* save the handles and enqueue the subkey */
+                                newCopyKeys->hKeySrc = KeyHandle;
+                                newCopyKeys->hKeyDest = NewKeyHandle;
+                                InsertTailList(&copyQueueHead,
+                                               &newCopyKeys->ListEntry);
+                            }
+                            else
+                            {
+                                NtClose(KeyHandle);
+                                NtClose(NewKeyHandle);
+                                
+                                Status2 = STATUS_INSUFFICIENT_RESOURCES;
+                                goto GoNextKey;
+                            }
+                        }
+                        else
+                        {
+                            NtClose(KeyHandle);
+                        }
+                    }
+                    
+GoNextKey:
+                    if (!NT_SUCCESS(Status2) && NT_SUCCESS(Status))
+                    {
+                        Status = Status2;
+                    }
+                    
+                    Index++;
+                }
+                else if (Status2 == STATUS_BUFFER_OVERFLOW)
+                {
+                    PVOID Buffer;
+
+                    ASSERT(BufferSize < BufferSizeRequired);
+
+                    Buffer = RtlReAllocateHeap(ProcessHeap,
+                                               0,
+                                               Info.Buffer,
+                                               BufferSizeRequired);
+                    if (Buffer != NULL)
+                    {
+                        Info.Buffer = Buffer;
+                        /* try again */
+                    }
+                    else
+                    {
+                        /* don't break, let's try to copy as many keys as possible */
+                        Status2 = STATUS_INSUFFICIENT_RESOURCES;
+                        Index++;
+
+                        if (NT_SUCCESS(Status))
+                        {
+                            Status = Status2;
+                        }
+                    }
+                }
+                else
+                {
+                    /* break to avoid an infinite loop in case of denied access or
+                       other errors! */
+                    if (Status2 != STATUS_NO_MORE_ENTRIES && NT_SUCCESS(Status))
+                    {
+                        Status = Status2;
+                    }
+
+                    break;
+                }
+            }
+
+            /* close the handles and remove the entry from the list */
+            if (copyKeys->hKeySrc != hKeySrc)
+            {
+                NtClose(copyKeys->hKeySrc);
+            }
+            if (copyKeys->hKeyDest != hKeyDest)
+            {
+                NtClose(copyKeys->hKeyDest);
+            }
+            
+            RemoveEntryList(&copyKeys->ListEntry);
+
+            RtlFreeHeap(ProcessHeap,
+                        0,
+                        copyKeys);
+        } while (!IsListEmpty(&copyQueueHead));
+    }
+    else
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    
+    RtlFreeHeap(ProcessHeap,
+                0,
+                Info.Buffer);
+
+    return Status;
+}
+
+
 /************************************************************************
  *  RegCopyTreeW
  *
- * @unimplemented
+ * @implemented
  */
 LONG STDCALL
 RegCopyTreeW(IN HKEY hKeySrc,
@@ -361,7 +645,7 @@
                                    NULL);
 
         Status = NtOpenKey(&SubKeyHandle,
-                           KEY_READ,
+                           KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
                            &ObjectAttributes);
         if (!NT_SUCCESS(Status))
         {
@@ -373,8 +657,8 @@
     else
         CurKey = KeyHandle;
     
-    /* FIXME - copy all keys and values recursively */
-    Status = STATUS_NOT_IMPLEMENTED;
+    Status = RegpCopyTree(CurKey,
+                          hKeyDest);
     
     if (SubKeyHandle != NULL)
     {
@@ -1135,7 +1419,7 @@
                     NtClose(delKeys->KeyHandle);
                 }
 
-                if (!NT_SUCCESS(Status))
+                if (NT_SUCCESS(Status))
                 {
                     /* don't break, let's try to delete as many keys as possible */
                     Status = Status2;