# HG changeset patch # User Aki Tuomi # Date 1487597316 -7200 # Node ID 538853d829269597a8c485dfeeca2768ed5ceb94 # Parent cb11cca4eaee25549541e23bf4c32f7750fe487a lib,lib-storage: Move hook building code to lib This allows it to be reused elsewhere diff -r cb11cca4eaee -r 538853d82926 src/lib-storage/mail-storage-hooks.c --- a/src/lib-storage/mail-storage-hooks.c Mon Feb 20 14:34:25 2017 +0200 +++ b/src/lib-storage/mail-storage-hooks.c Mon Feb 20 15:28:36 2017 +0200 @@ -2,6 +2,7 @@ #include "lib.h" #include "array.h" +#include "hook-build.h" #include "llist.h" #include "module-dir.h" #include "mail-user.h" @@ -15,28 +16,6 @@ bool forced; }; -struct hook_stack { - struct hook_stack *prev, *next; - - /* Pointer to vfuncs struct. This assumes that a struct containing - function pointers equals to an array of function pointers. Not - ANSI-C, but should work in all OSes supported by Dovecot. Much - easier anyway than doing this work manually.. */ - void (**vfuncs)(); - /* nonzero in the areas where vfuncs has been changed */ - void (**mask)(); -}; - -struct hook_build_context { - pool_t pool; - /* size of the vfuncs struct */ - size_t size; - /* number of function pointers in the struct */ - unsigned int count; - - struct hook_stack *head, *tail; -}; - static ARRAY(struct mail_storage_module_hooks) module_hooks = ARRAY_INIT; static ARRAY(const struct mail_storage_hooks *) internal_hooks = ARRAY_INIT; @@ -176,93 +155,6 @@ array_append_array(&user->hooks, &internal_hooks); } -static void hook_build_append(struct hook_build_context *ctx, void (**vfuncs)()) -{ - struct hook_stack *stack; - - stack = p_new(ctx->pool, struct hook_stack, 1); - stack->vfuncs = vfuncs; - stack->mask = p_malloc(ctx->pool, ctx->size); - DLLIST2_APPEND(&ctx->head, &ctx->tail, stack); -} - -static struct hook_build_context * -hook_build_init(void (**vfuncs)(), size_t size) -{ - struct hook_build_context *ctx; - pool_t pool; - - i_assert((size % sizeof(void (*)())) == 0); - - pool = pool_alloconly_create("hook build context", 2048); - ctx = p_new(pool, struct hook_build_context, 1); - ctx->pool = pool; - ctx->size = size; - ctx->count = size / sizeof(void (*)()); - hook_build_append(ctx, vfuncs); - return ctx; -} - -static void -hook_update_mask(struct hook_build_context *ctx, struct hook_stack *stack, - void (**vlast)()) -{ - unsigned int i; - - for (i = 0; i < ctx->count; i++) { - if (stack->vfuncs[i] != vlast[i]) { - i_assert(stack->vfuncs[i] != NULL); - stack->mask[i] = stack->vfuncs[i]; - } - } -} - -static void -hook_copy_stack(struct hook_build_context *ctx, struct hook_stack *stack) -{ - unsigned int i; - - i_assert(stack->next != NULL); - - for (i = 0; i < ctx->count; i++) { - if (stack->mask[i] == NULL) { - stack->vfuncs[i] = stack->next->vfuncs[i]; - stack->mask[i] = stack->next->mask[i]; - } - } -} - -static void hook_build_update(struct hook_build_context *ctx, void *_vlast) -{ - void (**vlast)() = _vlast; - struct hook_stack *stack; - - if (ctx->tail->vfuncs == vlast) { - /* no vfuncs overridden */ - return; - } - - /* ctx->vfuncs_stack->vfuncs points to the root vfuncs, - ctx->vfuncs_stack->next->vfuncs points to the first super function - that is being called, and so on. - - the previous plugin added its vfuncs to the stack tail. - vlast contains the previous plugin's super vfuncs, which is where - the next plugin should put its own vfuncs. - - first we'll need to figure out what vfuncs the previous plugin - changed and update the mask */ - hook_update_mask(ctx, ctx->tail, vlast); - - /* now go up in the stack as long as the mask isn't set, - and update the vfuncs */ - for (stack = ctx->tail->prev; stack != NULL; stack = stack->prev) - hook_copy_stack(ctx, stack); - - /* add vlast to stack */ - hook_build_append(ctx, vlast); -} - void hook_mail_user_created(struct mail_user *user) { const struct mail_storage_hooks *const *hooks; @@ -279,7 +171,7 @@ } T_END; } user->vlast = NULL; - pool_unref(&ctx->pool); + hook_build_deinit(&ctx); } void hook_mail_namespace_storage_added(struct mail_namespace *ns) @@ -333,7 +225,7 @@ } T_END; } storage->vlast = NULL; - pool_unref(&ctx->pool); + hook_build_deinit(&ctx); } void hook_mailbox_list_created(struct mailbox_list *list) @@ -350,7 +242,7 @@ } T_END; } list->vlast = NULL; - pool_unref(&ctx->pool); + hook_build_deinit(&ctx); } void hook_mailbox_allocated(struct mailbox *box) @@ -367,7 +259,7 @@ } T_END; } box->vlast = NULL; - pool_unref(&ctx->pool); + hook_build_deinit(&ctx); } void hook_mailbox_opened(struct mailbox *box) @@ -396,5 +288,5 @@ } T_END; } pmail->vlast = NULL; - pool_unref(&ctx->pool); + hook_build_deinit(&ctx); } diff -r cb11cca4eaee -r 538853d82926 src/lib/Makefile.am --- a/src/lib/Makefile.am Mon Feb 20 14:34:25 2017 +0200 +++ b/src/lib/Makefile.am Mon Feb 20 15:28:36 2017 +0200 @@ -50,6 +50,7 @@ hmac.c \ hmac-cram-md5.c \ home-expand.c \ + hook-build.c \ hostpid.c \ imem.c \ ipwd.c \ @@ -196,6 +197,7 @@ hmac.h \ hmac-cram-md5.h \ home-expand.h \ + hook-build.h \ hostpid.h \ imem.h \ ipwd.h \ diff -r cb11cca4eaee -r 538853d82926 src/lib/hook-build.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/hook-build.c Mon Feb 20 15:28:36 2017 +0200 @@ -0,0 +1,121 @@ +/* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "llist.h" +#include "hook-build.h" + +struct hook_stack { + struct hook_stack *prev, *next; + + /* Pointer to vfuncs struct. This assumes that a struct containing + function pointers equals to an array of function pointers. Not + ANSI-C, but should work in all OSes supported by Dovecot. Much + easier anyway than doing this work manually.. */ + void (**vfuncs)(); + /* nonzero in the areas where vfuncs has been changed */ + void (**mask)(); +}; + +struct hook_build_context { + pool_t pool; + /* size of the vfuncs struct */ + size_t size; + /* number of function pointers in the struct */ + unsigned int count; + + struct hook_stack *head, *tail; +}; + +static void hook_build_append(struct hook_build_context *ctx, void (**vfuncs)()) +{ + struct hook_stack *stack; + + stack = p_new(ctx->pool, struct hook_stack, 1); + stack->vfuncs = vfuncs; + stack->mask = p_malloc(ctx->pool, ctx->size); + DLLIST2_APPEND(&ctx->head, &ctx->tail, stack); +} + +struct hook_build_context *hook_build_init(void (**vfuncs)(), size_t size) +{ + struct hook_build_context *ctx; + pool_t pool; + + i_assert((size % sizeof(void (*)())) == 0); + + pool = pool_alloconly_create("hook build context", 2048); + ctx = p_new(pool, struct hook_build_context, 1); + ctx->pool = pool; + ctx->size = size; + ctx->count = size / sizeof(void (*)()); + hook_build_append(ctx, vfuncs); + return ctx; +} + +static void +hook_update_mask(struct hook_build_context *ctx, struct hook_stack *stack, + void (**vlast)()) +{ + unsigned int i; + + for (i = 0; i < ctx->count; i++) { + if (stack->vfuncs[i] != vlast[i]) { + i_assert(stack->vfuncs[i] != NULL); + stack->mask[i] = stack->vfuncs[i]; + } + } +} + +static void +hook_copy_stack(struct hook_build_context *ctx, struct hook_stack *stack) +{ + unsigned int i; + + i_assert(stack->next != NULL); + + for (i = 0; i < ctx->count; i++) { + if (stack->mask[i] == NULL) { + stack->vfuncs[i] = stack->next->vfuncs[i]; + stack->mask[i] = stack->next->mask[i]; + } + } +} + +void hook_build_update(struct hook_build_context *ctx, void *_vlast) +{ + void (**vlast)() = _vlast; + struct hook_stack *stack; + + if (ctx->tail->vfuncs == vlast) { + /* no vfuncs overridden */ + return; + } + + /* ctx->vfuncs_stack->vfuncs points to the root vfuncs, + ctx->vfuncs_stack->next->vfuncs points to the first super function + that is being called, and so on. + + the previous plugin added its vfuncs to the stack tail. + vlast contains the previous plugin's super vfuncs, which is where + the next plugin should put its own vfuncs. + + first we'll need to figure out what vfuncs the previous plugin + changed and update the mask */ + hook_update_mask(ctx, ctx->tail, vlast); + + /* now go up in the stack as long as the mask isn't set, + and update the vfuncs */ + for (stack = ctx->tail->prev; stack != NULL; stack = stack->prev) + hook_copy_stack(ctx, stack); + + /* add vlast to stack */ + hook_build_append(ctx, vlast); +} + +void hook_build_deinit(struct hook_build_context **_ctx) +{ + struct hook_build_context *ctx = *_ctx; + *_ctx = NULL; + pool_unref(&ctx->pool); +} diff -r cb11cca4eaee -r 538853d82926 src/lib/hook-build.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/hook-build.h Mon Feb 20 15:28:36 2017 +0200 @@ -0,0 +1,19 @@ +/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */ +#ifndef HOOK_BUILD_H +#define HOOK_BUILD_H 1 + +struct hook_build_context; +struct hook_stack; + +/* Initialize new hook building context, vfuncs should point to + the functions table that is being manipulated, and size should be + the size of this table. */ +struct hook_build_context *hook_build_init(void (**vfuncs)(), size_t size); + +/* This is called after a hook may have updated vfuncs */ +void hook_build_update(struct hook_build_context *ctx, void *_vlast); + +/* Free memory used by build context */ +void hook_build_deinit(struct hook_build_context **_ctx); + +#endif