/* * Copyright (c) 2003-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: cdbfs.c,v 1.12 2007/06/15 02:52:59 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/fs.h" #include "sm/cdbfs.h" /* Note: this "knows" about the hashing algorithm in cdb.c! */ #define CDB_DIRS 16 /* Comments: It is not so useful to have fs_ctx "hidden" in this struct, it should be passed in and be shared with others, because there are more DBs on disk and hence more directories need to be "monitored". Those directories may "overlap" with the ones used for CDB, hence it is not possible to use disjunct fs_ctx for different DBs. */ struct cdb_fsctx_S { fs_ctx_P cfx_fs_ctx; char cfx_dirs[CDB_DIRS][PATH_MAX]; int cfx_fs_idx[CDB_DIRS]; }; /* ** CDB_FSCTX_CLOSE -- close a CDB FS context ** ** Parameters: ** cdb_fsctx -- CDB context ** ** Returns: ** SM_SUCCESS ** ** Last code review: 2005-03-17 18:40:13 ** Last code change: */ sm_ret_T cdb_fsctx_close(cdb_fsctx_P cdb_fsctx) { if (cdb_fsctx == NULL) return SM_SUCCESS; sm_free_size(cdb_fsctx, sizeof(*cdb_fsctx)); return SM_SUCCESS; } /* ** CDB_FSCTX_OPEN -- open a CDB FS context ** ** Parameters: ** fs_ctx -- FS context ** base_path -- path to base directory ** pcdb_fsctx -- (pointer to) CDB FS context (output) ** pkbfree -- (pointer to) free space (KB) (output) ** ** Returns: ** usual sm_error code; ENOMEM, etc ** ** Last code review: 2005-03-17 21:38:35 ** Last code change: */ sm_ret_T cdb_fsctx_open(fs_ctx_P fs_ctx, const char *base_path, cdb_fsctx_P *pcdb_fsctx, ulong *pkbfree) { sm_ret_T ret; int i, j; size_t l; ulong kbfree, freemin; cdb_fsctx_P cdb_fsctx; SM_REQUIRE(pcdb_fsctx != NULL); cdb_fsctx = (cdb_fsctx_P) sm_zalloc(sizeof(*cdb_fsctx)); if (cdb_fsctx == NULL) return sm_error_temp(SM_EM_CDB, ENOMEM); for (i = 0; i < CDB_DIRS; i++) { char dir[2]; if (base_path != NULL) { l = strlcpy(cdb_fsctx->cfx_dirs[i], base_path, sizeof(cdb_fsctx->cfx_dirs[i])); if (l >= sizeof(cdb_fsctx->cfx_dirs[i])) { ret = sm_error_perm(SM_EM_EDB, SM_E_2BIG); goto error; } } if (i < 10) dir[0] = '0' + i; else dir[0] = 'A' + i - 10; dir[1] = '\0'; l = strlcat(cdb_fsctx->cfx_dirs[i], dir, sizeof(cdb_fsctx->cfx_dirs[i])); if (l >= sizeof(cdb_fsctx->cfx_dirs[i])) { ret = sm_error_perm(SM_EM_EDB, SM_E_2BIG); goto error; } } SM_IS_FS_CTX(fs_ctx); cdb_fsctx->cfx_fs_ctx = fs_ctx; freemin = LONG_MAX; for (i = 0; i < CDB_DIRS; i++) { ret = fs_new(cdb_fsctx->cfx_fs_ctx, cdb_fsctx->cfx_dirs[i], &j); if (sm_is_err(ret)) goto error; cdb_fsctx->cfx_fs_idx[i] = j; ret = fs_getfree(cdb_fsctx->cfx_fs_ctx, j, &kbfree); if (sm_is_err(ret)) goto error; if (kbfree < freemin) freemin = kbfree; } *pkbfree = freemin; *pcdb_fsctx = cdb_fsctx; return SM_SUCCESS; error: if (cdb_fsctx != NULL) sm_free_size(cdb_fsctx, sizeof(*cdb_fsctx)); return ret; } /* ** CDB_SZ_CHG -- change size in CDB ** ** Parameters: ** cdb_fsctx -- CDB context ** cdb_id -- (transaction id) ** size -- change of size ** pkbfree -- (pointer to) free space (KB) (output) ** ** Returns: ** usual sm_error code; EINVAL, etc ** ** Last code review: 2005-03-17 21:39:16 ** Last code change: */ sm_ret_T cdb_sz_chg(cdb_fsctx_P cdb_fsctx, char *cdb_id, long size, ulong *pkbfree) { size_t l; char c; int i; SM_REQUIRE(cdb_fsctx != NULL); SM_REQUIRE(cdb_id != NULL); l = strlen(cdb_id) + 3; if (l <= 6) return sm_error_perm(SM_EM_CDB, EINVAL); c = cdb_id[l - 6]; if (c >= '0' && c <= '9') i = c - '0'; else if (c >= 'A' && c <= 'F') i = c - 'A' + 10; else return sm_error_perm(SM_EM_CDB, EINVAL); SM_ASSERT(i >= 0 && i < CDB_DIRS); return fs_chgfree(cdb_fsctx->cfx_fs_ctx, cdb_fsctx->cfx_fs_idx[i], size, pkbfree); } /* ** CDB_FS_GETFREE -- get free space in CDB FS ** (minimum of all subdirectories) ** ** Parameters: ** cdb_fs_ctx -- CDB FS context ** pkbfree -- (pointer to) free space (KB) (output) ** ** Returns: ** usual sm_error code ** ** Last code review: 2005-03-17 21:40:52 ** Last code change: */ sm_ret_T cdb_fs_getfree(cdb_fsctx_P cdb_fsctx, ulong *pkbfree) { sm_ret_T ret; int i; ulong kbfree, freemin; SM_REQUIRE(cdb_fsctx != NULL); SM_REQUIRE(pkbfree != NULL); ret = SM_SUCCESS; freemin = LONG_MAX; for (i = 0; i < CDB_DIRS; i++) { ret = fs_getfree(cdb_fsctx->cfx_fs_ctx, cdb_fsctx->cfx_fs_idx[i], &kbfree); if (!sm_is_err(ret) && kbfree < freemin) freemin = kbfree; } *pkbfree = freemin; return ret; }