/* * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: edbcmv.c,v 1.7 2006/03/13 18:41:33 ca Exp $") #include "sm/error.h" #include "sm/memops.h" #include "sm/heap.h" #include "sm/assert.h" #include "sm/str.h" #include "sm/edbc.h" #include "edbc.h" #include "sm/qmgrdbg.h" /* ** EDBC_MV -- change an entry in envelope database cache ** ** Parameters: ** edbc_ctx -- edbc context ** edbc_node -- edbc node ** next_try -- next time to try ** ** Returns: ** usual sm_error code. ** ** Locking: must be performed by caller. */ sm_ret_T edbc_mv(edbc_ctx_P edbc_ctx, edbc_node_P edbc_node, time_T next_try) { sm_ret_T ret; edbc_node_T edbc_node_search; edbc_tnode_T edbc_tnode; edbc_tnode_P edbc_tnode_ret, edbc_tnode_new; /* ** Note: this function isn't as useful as it was supposed to be ** because it was intended to be "always" successful even if ** resources are unavailable. However, that doesn't work because ** it may be required to create a new tnode. Currently it is always ** allocated to avoid problems "in the middle" of the operation. ** ** The algorithm should be like this: ** locate tnode of current place (tnode_old) ** locate tnode of new place (tnode_new) ** if tnode_new == NULL ** if tnode_old contains only one node: reuse this tnode ** else { alloc new tnode; if NULL: return error; } ** now all resources are available, the old data can be ** removed, the new brought into place... */ SM_REQUIRE(edbc_ctx != NULL); SM_REQUIRE(edbc_node != NULL); edbc_tnode_new = NULL; sm_memzero(&edbc_node_search, sizeof(edbc_node_search)); sm_memzero(&edbc_tnode, sizeof(edbc_tnode)); ECNL_INIT(&(edbc_tnode.ectn_hd)); ECNL_APP(&(edbc_tnode.ectn_hd), &edbc_node_search); edbc_node_search.ecn_next_try = edbc_node->ecn_next_try; edbc_tnode_ret = RB_FIND(edbc_tree_S, &edbc_ctx->edbc_root, &edbc_tnode); if (edbc_tnode_ret == NULL) return sm_error_temp(SM_EM_Q_EDBC, SM_E_NOTFOUND); /* this might not be needed... */ edbc_tnode_new = (edbc_tnode_P) sm_zalloc(sizeof(*edbc_tnode_new)); if (edbc_tnode_new == NULL) return sm_error_temp(SM_EM_Q_EDBC, ENOMEM); ECNL_REMOVE(&edbc_tnode_ret->ectn_hd, edbc_node); if (ECNL_EMPTY(&edbc_tnode_ret->ectn_hd)) { if (RB_REMOVE(edbc_tree_S, &edbc_ctx->edbc_root, edbc_tnode_ret) == NULL) { /* OOPS now the entry is gone... */ return sm_error_temp(SM_EM_Q_EDBC, SM_E_UNEXPECTED); } SM_FREE(edbc_tnode_ret); edbc_tnode_ret = NULL; } sm_memzero(&edbc_tnode, sizeof(edbc_tnode)); ECNL_INIT(&(edbc_tnode.ectn_hd)); ECNL_APP(&(edbc_tnode.ectn_hd), edbc_node); edbc_node->ecn_next_try = next_try; edbc_tnode_ret = RB_FIND(edbc_tree_S, &edbc_ctx->edbc_root, &edbc_tnode); if (edbc_tnode_ret == NULL) { ECNL_INIT(&edbc_tnode_new->ectn_hd); ECNL_APP(&edbc_tnode_new->ectn_hd, edbc_node); edbc_tnode_ret = RB_INSERT(edbc_tree_S, &edbc_ctx->edbc_root, edbc_tnode_new); if (edbc_tnode_ret != NULL) { /* Internal error? Should not happen! */ ret = sm_error_perm(SM_EM_Q_EDBC, EEXIST); goto error; } } else { /* Check first whether it's there? */ ECNL_APP(&edbc_tnode_ret->ectn_hd, edbc_node); } return SM_SUCCESS; error: SM_FREE(edbc_tnode_new); return ret; }