Fix PReg write support.
authorWilco Baan Hofman <wilco@synlap.(none)>
Tue, 15 Apr 2008 17:57:29 +0000 (19:57 +0200)
committerWilco Baan Hofman <wilco@synlap.(none)>
Tue, 15 Apr 2008 17:57:29 +0000 (19:57 +0200)
Add tests for patch files (.REG and PReg).
(This used to be commit 497977c36c621a4820be51cbcb7b78eac1e292b7)

source4/lib/registry/patchfile.c
source4/lib/registry/patchfile_preg.c
source4/lib/registry/registry.h
source4/lib/registry/tests/diff.c

index eaeef341bbace37a988ab4e8610e3163b72f0737..0ede3106f00dceecb9e95deee19aa503e867c1a3 100644 (file)
@@ -320,12 +320,33 @@ static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
 {
        struct registry_context *ctx = (struct registry_context *)_ctx;
        struct registry_key *tmp;
+       char *buf, *buf_ptr;
        WERROR error;
 
+       /* Recursively create the path */
+       buf = talloc_strdup(ctx, key_name);
+       buf_ptr = buf;
+
+       while (*buf_ptr++ != '\0' ) {
+               if (*buf_ptr == '\\') {
+                       *buf_ptr = '\0';
+                       error = reg_key_add_abs(ctx, ctx, buf, 0, NULL, &tmp);
+
+                       if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
+                                   !W_ERROR_IS_OK(error)) {
+                               DEBUG(0, ("Error adding new key '%s': %s\n",
+                                       key_name, win_errstr(error)));
+                               return error;
+                       }
+                       *buf_ptr++ = '\\';
+               }
+       }
+
+       /* Add the key */
        error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
 
        if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
-           !W_ERROR_IS_OK(error)) {
+                   !W_ERROR_IS_OK(error)) {
                DEBUG(0, ("Error adding new key '%s': %s\n",
                        key_name, win_errstr(error)));
                return error;
index a28096517c685d46e26967e612a41de7ba5eb85f..ea41a9e21bbd49519cf2743ed487ad0c1aa28ead 100644 (file)
 #include "lib/registry/registry.h"
 #include "system/filesys.h"
 #include "param/param.h"
+#include "librpc/gen_ndr/winreg.h"
 
 struct preg_data {
        int fd;
+       TALLOC_CTX *ctx;
+       struct smb_iconv_convenience *ic;
 };
 
 static WERROR preg_read_utf16(struct smb_iconv_convenience *ic, int fd, char *c)
@@ -38,25 +41,69 @@ static WERROR preg_read_utf16(struct smb_iconv_convenience *ic, int fd, char *c)
        push_codepoint(ic, c, v);
        return WERR_OK;
 }
-
-/* FIXME These functions need to be implemented */
-static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
+static WERROR preg_write_utf16(struct smb_iconv_convenience *ic, int fd, const char *string)
 {
-       return WERR_NOT_SUPPORTED;
+       codepoint_t v;
+       uint16_t i;
+       size_t size;
+
+       for (i = 0; i < strlen(string); i+=size) {
+               v = next_codepoint(ic, &string[i], &size);
+               if (write(fd, &v, 2) < 2) {
+                       return WERR_GENERAL_FAILURE;
+               }
+       }
+       return WERR_OK;
 }
-
-static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
+/* PReg does not support adding keys. */
+static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
 {
-       return WERR_NOT_SUPPORTED;
+       return WERR_OK;
 }
 
 static WERROR reg_preg_diff_set_value(void *_data, const char *key_name,
                                      const char *value_name,
                                      uint32_t value_type, DATA_BLOB value_data)
 {
-       return WERR_NOT_SUPPORTED;
+       struct preg_data *data = _data;
+       uint32_t buf;
+       
+       preg_write_utf16(data->ic, data->fd, "[");
+       preg_write_utf16(data->ic, data->fd, key_name);
+       preg_write_utf16(data->ic, data->fd, ";");
+       preg_write_utf16(data->ic, data->fd, value_name);
+       preg_write_utf16(data->ic, data->fd, ";");
+       SIVAL(&buf, 0, value_type);
+       write(data->fd, &buf, sizeof(uint32_t));
+       preg_write_utf16(data->ic, data->fd, ";");
+       SIVAL(&buf, 0, value_data.length);
+       write(data->fd, &buf, sizeof(uint32_t));
+       preg_write_utf16(data->ic, data->fd, ";");
+       write(data->fd, value_data.data, value_data.length);
+       preg_write_utf16(data->ic, data->fd, "]");
+       
+       return WERR_OK;
 }
 
+static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
+{
+       struct preg_data *data = _data;
+       char *parent_name;
+       DATA_BLOB blob;
+
+       parent_name = talloc_strndup(data->ctx, key_name, strrchr(key_name, '\\')-key_name);
+       blob.data = (void *)talloc_strndup(data->ctx, key_name, 
+                       strlen(key_name)-(strrchr(key_name, '\\')-key_name));
+       blob.length = strlen((char *)blob.data)+1;
+       
+
+       /* FIXME: These values should be accumulated to be written at done(). */
+       reg_preg_diff_set_value(_data, parent_name, "**DeleteKeys", REG_SZ, blob);
+               
+       return WERR_OK;
+}
+
+/* FIXME These functions need to be implemented */
 static WERROR reg_preg_diff_del_value(void *_data, const char *key_name,
                                      const char *value_name)
 {
@@ -81,6 +128,7 @@ static WERROR reg_preg_diff_done(void *_data)
  * Save registry diff
  */
 _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
+                                  struct smb_iconv_convenience *ic,
                                   struct reg_diff_callbacks **callbacks,
                                   void **callback_data)
 {
@@ -103,10 +151,14 @@ _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
        } else {
                data->fd = STDOUT_FILENO;
        }
+
        memcpy(preg_header.hdr, "PReg", 4);
        SIVAL(&preg_header, 4, 1);
        write(data->fd, (uint8_t *)&preg_header,8);
 
+       data->ctx = ctx;
+       data->ic = ic;
+
        *callbacks = talloc(ctx, struct reg_diff_callbacks);
 
        (*callbacks)->add_key = reg_preg_diff_add_key;
@@ -179,7 +231,8 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
                       *buf_ptr != ';' && buf_ptr-buf < buf_size) {
                        buf_ptr++;
                }
-               key = talloc_asprintf(mem_ctx, "\\%s", buf);
+               buf[buf_ptr-buf] = '\0';
+               key = talloc_strdup(mem_ctx, buf);
 
                /* Get the name */
                buf_ptr = buf;
@@ -187,6 +240,7 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
                       *buf_ptr != ';' && buf_ptr-buf < buf_size) {
                        buf_ptr++;
                }
+               buf[buf_ptr-buf] = '\0';
                value_name = talloc_strdup(mem_ctx, buf);
 
                /* Get the type */
index 573379aff5017a8a9e5c734328132db36b46077d..6a98a6063362fdb9cad801ed0c485f59333e9bfb 100644 (file)
@@ -493,6 +493,7 @@ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename,
                            struct reg_diff_callbacks **callbacks,
                            void **callback_data);
 WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
+                         struct smb_iconv_convenience *ic,
                          struct reg_diff_callbacks **callbacks,
                          void **callback_data);
 WERROR reg_generate_diff_key(struct registry_key *oldkey,
index da6234212449b42cbb3d050be78775ccc6461b28..4bd868ea513653cec125b3948efd50efb08813e3 100644 (file)
@@ -24,6 +24,7 @@
 #include "lib/registry/registry.h"
 #include "torture/torture.h"
 #include "librpc/gen_ndr/winreg.h"
+#include "param/param.h"
 
 struct diff_tcase_data {
        struct registry_context *r1_ctx;
@@ -56,13 +57,12 @@ static bool test_generate_diff(struct torture_context *tctx, void *tcase_data)
 static bool test_diff_load(struct torture_context *tctx, void *tcase_data)
 {
        struct diff_tcase_data *td = tcase_data;
-       struct smb_iconv_convenience *iconv_convenience;
+       struct smb_iconv_convenience *ic;
        struct reg_diff_callbacks *callbacks;
        void *data;
        WERROR error;
 
-       iconv_convenience = smb_iconv_convenience_init(tctx, "CP850", "UTF-8", 1);
-
+       ic = lp_iconv_convenience(tctx->lp_ctx);
 
        error = reg_diff_load(td->filename, iconv_convenience, callbacks, data);
        torture_assert_werr_ok(tctx, error, "reg_diff_load");
@@ -244,13 +244,16 @@ static bool diff_setup_tcase(struct torture_context *tctx, void **data)
 static bool diff_setup_preg_tcase (struct torture_context *tctx, void **data)
 {
        struct diff_tcase_data *td;
+       struct smb_iconv_convenience *ic;
        WERROR error;
 
        diff_setup_tcase(tctx, data);
        td = *data;
-       
+
+       ic = lp_iconv_convenience(tctx->lp_ctx);
+
        td->filename = talloc_asprintf(tctx, "%s/test.pol", td->tempdir);
-       error = reg_preg_diff_save(tctx, td->filename, &td->callbacks, &td->callback_data);
+       error = reg_preg_diff_save(tctx, td->filename, ic, &td->callbacks, &td->callback_data);
        torture_assert_werr_ok(tctx, error, "reg_preg_diff_save");
 
        return true;
@@ -259,16 +262,16 @@ static bool diff_setup_preg_tcase (struct torture_context *tctx, void **data)
 static bool diff_setup_dotreg_tcase (struct torture_context *tctx, void **data)
 {
        struct diff_tcase_data *td;
-       struct smb_iconv_convenience *iconv_convenience;
+       struct smb_iconv_convenience *ic;
        WERROR error;
 
        diff_setup_tcase(tctx, data);
        td = *data;
 
-       iconv_convenience = smb_iconv_convenience_init(tctx, "CP850", "UTF-8", 1);
+       ic = lp_iconv_convenience(tctx->lp_ctx);
        
        td->filename = talloc_asprintf(tctx, "%s/test.reg", td->tempdir);
-       error = reg_dotreg_diff_save(tctx, td->filename, iconv_convenience, &td->callbacks, &td->callback_data);
+       error = reg_dotreg_diff_save(tctx, td->filename, ic, &td->callbacks, &td->callback_data);
        torture_assert_werr_ok(tctx, error, "reg_dotreg_diff_save");
 
        return true;