/* MdbDeleteEntry: Deletes an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBDeleteEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_MODIFICATION pMods, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; VDIR_MODIFICATION * mod = NULL; PVDIR_DB_TXN pTxn = NULL; assert( pBECtx && pBECtx->pBEPrivate && pMods && pEntry ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; // Delete child from the parentId index dwError = MDBDeleteParentIdIndex( pBECtx, &(pEntry->pdn), pEntry->eId ); BAIL_ON_VMDIR_ERROR(dwError); for (mod = pMods; mod != NULL; mod = mod->next) { switch (mod->operation) { case MOD_OP_DELETE: if ((dwError = MdbUpdateIndicesForAttr( pBECtx->pBE, pTxn, &(pEntry->dn), &(mod->attr.type), mod->attr.vals, mod->attr.numVals, pEntry->eId, BE_INDEX_OP_TYPE_DELETE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } break; default: assert( FALSE ); } } // Delete Entry Blob if ((dwError = MDBDeleteEntryBlob(pBECtx, pEntry->eId)) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "MDBDeleteEntryBlob"); BAIL_ON_VMDIR_ERROR( dwError ); } cleanup: return dwError; error: VMDIR_SET_BACKEND_ERROR(dwError); // if dwError no in BE space, set to ERROR_BACKEND_ERROR VMDIR_LOG_ERROR(LDAP_DEBUG_BACKEND, "VmDirMDBDeleteEntry: failed: error=%d,DN=%s", dwError, VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val)); goto cleanup; }
/* MdbModifyEntry: Updates an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBModifyEntry( PVDIR_BACKEND_CTX pBECtx, VDIR_MODIFICATION* pMods, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; VDIR_BERVALUE newEncodedEntry = VDIR_BERVALUE_INIT; VDIR_MODIFICATION * mod = NULL; PVDIR_DB_TXN pTxn = NULL; assert( pBECtx && pBECtx->pBEPrivate && pMods && pEntry ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; dwError = VmDirEncodeEntry( pEntry, &newEncodedEntry ); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_SAFE_FREE_MEMORY( pEntry->encodedEntry ); // entry takes over the responsibility to free newEncodedEntry.lberbv.bv_val pEntry->encodedEntry = (unsigned char *)newEncodedEntry.lberbv.bv_val; // Create/Delete appropriate indices for indexed attributes. for (mod = pMods; mod != NULL; mod = mod->next) { if (mod->ignore) { continue; } switch (mod->operation) { case MOD_OP_ADD: if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(mod->attr.type), mod->attr.vals, mod->attr.numVals, pEntry->eId, BE_INDEX_OP_TYPE_CREATE)) != 0) { dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } break; case MOD_OP_DELETE: if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(mod->attr.type), mod->attr.vals, mod->attr.numVals, pEntry->eId, BE_INDEX_OP_TYPE_DELETE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } break; case MOD_OP_REPLACE: default: assert( FALSE ); } if ((dwError = MdbUpdateAttrMetaData( pTxn, &(mod->attr), pEntry->eId, BE_INDEX_OP_TYPE_UPDATE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } } // Update Entry DB. if ((dwError = MdbCreateEIDIndex(pTxn, pEntry->eId, &newEncodedEntry, FALSE /* update current eId key */)) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "CreateEIDIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } cleanup: return dwError; error: VMDIR_SET_BACKEND_ERROR(dwError); // if dwError no in BE space, set to ERROR_BACKEND_ERROR VMDIR_LOG_ERROR(LDAP_DEBUG_BACKEND, "ModifyEntry failed: error=%d,DN=%s", dwError, VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val)); goto cleanup; }
/* MdbAddEntry: Creates an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBAddEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_ENTRY pEntry) { DWORD dwError = 0; ENTRYID entryId = 0; VDIR_DB_TXN* pTxn = NULL; VDIR_BERVALUE encodedEntry = VDIR_BERVALUE_INIT; VDIR_ATTRIBUTE * nextAttr = NULL; assert( pEntry && pBECtx && pBECtx->pBEPrivate ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; dwError = VmDirEncodeEntry( pEntry, &encodedEntry ); BAIL_ON_VMDIR_ERROR(dwError); if (pEntry->eId != 0) // Reserved entries have eId already { entryId = pEntry->eId; } else { VDIR_DB_DBT EIDkey = {0}; VDIR_DB_DBT EIDvalue = {0}; unsigned char EIDKeyBytes[sizeof( ENTRYID )] = {0}; unsigned char EIDValueBytes[sizeof( ENTRYID )] = {0}; EIDkey.mv_data = &EIDKeyBytes[0]; MDBEntryIdToDBT(BE_MDB_ENTRYID_SEQ_KEY, &EIDkey); dwError = mdb_get(pTxn, gVdirMdbGlobals.mdbSeqDBi, &EIDkey, &EIDvalue); BAIL_ON_VMDIR_ERROR(dwError); assert( EIDvalue.mv_size == sizeof(ENTRYID) ); entryId = *((ENTRYID*)EIDvalue.mv_data); *((ENTRYID*)&EIDValueBytes[0]) = entryId + 1; EIDvalue.mv_data = &EIDValueBytes[0]; EIDvalue.mv_size = sizeof(ENTRYID); dwError = mdb_put(pTxn, gVdirMdbGlobals.mdbSeqDBi, &EIDkey, &EIDvalue, BE_DB_FLAGS_ZERO); BAIL_ON_VMDIR_ERROR(dwError); } assert( entryId > 0 ); if ((dwError = MDBCreateParentIdIndex(pBECtx, &(pEntry->pdn), entryId)) != 0) { dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND, ERROR_BACKEND_PARENT_NOTFOUND, pBECtx, "CreateParentIdIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } // Update DN index first. this make sure we always return ERROR_BACKEND_ENTRY_EXISTS in such case. for (nextAttr = pEntry->attrs; nextAttr != NULL; nextAttr = nextAttr->next) { if (VmDirStringCompareA(nextAttr->type.lberbv.bv_val, ATTR_DN, FALSE) == 0) { // make sure we store normalized DN value. dwError = VmDirNormalizeDN( &(nextAttr->vals[0]), pEntry->pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(nextAttr->type), nextAttr->vals, nextAttr->numVals, entryId, BE_INDEX_OP_TYPE_CREATE)) != 0) { dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_ENTRY_EXISTS, pBECtx, VDIR_SAFE_STRING(nextAttr->vals[0].bvnorm_val)); BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = MdbUpdateAttrMetaData( pTxn, nextAttr, entryId, BE_INDEX_OP_TYPE_CREATE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "UpdateDNAttrMetaData"); BAIL_ON_VMDIR_ERROR( dwError ); } } } // Update remaining indices for (nextAttr = pEntry->attrs; nextAttr != NULL; nextAttr = nextAttr->next) { if (VmDirStringCompareA(nextAttr->type.lberbv.bv_val, ATTR_DN, FALSE) != 0) { if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(nextAttr->type), nextAttr->vals, nextAttr->numVals, entryId, BE_INDEX_OP_TYPE_CREATE)) != 0) { dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, VDIR_SAFE_STRING(nextAttr->type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = MdbUpdateAttrMetaData( pTxn, nextAttr, entryId, BE_INDEX_OP_TYPE_CREATE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(nextAttr->type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } } } // Update entry/blob database if ((dwError = MdbCreateEIDIndex(pTxn, entryId, &encodedEntry, TRUE /* 1st time new entry creation */)) != 0) { dwError = MDBToBackendError(dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, "CreateEIDIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } cleanup: VMDIR_SAFE_FREE_MEMORY( encodedEntry.lberbv.bv_val ); return dwError; error: // TODO set pBECtx->pszBEErrorMsg? VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEAddEntry DN (%s), (%u)(%s)", VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val), dwError, VDIR_SAFE_STRING(pBECtx->pszBEErrorMsg)); VMDIR_SET_BACKEND_ERROR(dwError); // if dwError no in BE space, set to ERROR_BACKEND_ERROR goto cleanup; }