/*
 * Copyright (c) 2004-2006 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: t-cdb-0.c,v 1.15 2006/07/18 02:43:18 ca Exp $")

#include "sm/assert.h"
#include "sm/error.h"
#include "sm/io.h"
#include "sm/sysexits.h"
#include "sm/cdb.h"
#if TEST_CDB_BC
#include "cdbbf.h"
#endif
#include "sm/test.h"

#define SM_BUF_SIZE	(4 * 1024)
#define SM_BF_SIZE	(8 * 1024)

#if TEST_CDB_BC
extern sm_stream_T SmCDBStL;
# define CDB_OPEN_WRITE(cdb_ctx, ta_id, dfp, mode, instance, cdb_id) cdb_open_wr_vector(cdb_ctx, ta_id, dfp, mode, instance, &SmCDBStL, SM_BF_SIZE, cdb_id)
#else
# define CDB_OPEN_WRITE(cdb_ctx, ta_id, dfp, mode, instance, cdb_id) cdb_open_write(cdb_ctx, ta_id, dfp, mode, instance, cdb_id)
#endif

/*
**  CDB_TEST -- simple CDB test
**
**	Parameters:
**		base -- base name for CDB
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
cdb_test(const char *base)
{
	size_t i;
	sm_ret_T ret;
	cdb_ctx_P cdb_ctx;
	cdb_id_P cdb_id;
	sm_file_T *dfp;
	ssize_t byteswritten, bytesread;
#if TEST_CDB_BC
	sm_file_T *dfpr;
	int r;
	struct stat sb;
#endif
	sessta_id_T ta_id;
	uchar wbuf[SM_BUF_SIZE], wbuf2[SM_BUF_SIZE], rbuf[SM_BUF_SIZE];

	dfp = NULL;
	cdb_id = NULL;
	SM_ASSERT(sizeof(rbuf) == sizeof(wbuf));
	ret = cdb_start(base, &cdb_ctx);
	SM_TEST_E(SM_SUCCESS == ret);

	for (i = 0; i < sizeof(wbuf); i++)
	{
		wbuf[i] = 'A' + (i % 32);
		wbuf2[i] = '0' + (i % 32);
		if (i % 78 == 0)
			wbuf[i] = wbuf2[i] = '\n';
	}

	sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT,
		(ulonglong_T) 1, 2);

	ret = CDB_OPEN_WRITE(cdb_ctx, ta_id, dfp, SM_IO_WREXCL, 0, &cdb_id);
	SM_TEST_E(SM_SUCCESS == ret);

	/* write some stuff ... */
	ret = cdb_write(cdb_ctx, dfp, (uchar *) wbuf, sizeof(wbuf),
			&byteswritten);
	SM_TEST_E(SM_SUCCESS == ret);
	SM_TEST(byteswritten == sizeof(wbuf));

#if TEST_CDB_BC
	SM_TEST_E(cdb_id != NULL);
	r = stat(cdbf_path(dfp), &sb);
	SM_TEST(r < 0);
	SM_TEST(ENOENT == errno);
#endif

	ret = cdb_commit(cdb_ctx, dfp);
	SM_TEST(SM_SUCCESS == ret);

#if TEST_CDB_BC
	SM_TEST_E(cdb_id != NULL);
	r = stat(cdbf_path(dfp), &sb);
	SM_TEST(0 == r);
#endif

	ret = cdb_close(cdb_ctx, dfp, SM_IO_CF_NONE);
	SM_TEST(SM_SUCCESS == ret);

#if !TEST_CDB_BC
	/* fails, file exists */
	ret = cdb_open_write(cdb_ctx, ta_id, dfp, SM_IO_WREXCL, 0, NULL);
	SM_TEST(ret != SM_SUCCESS);
	if (!sm_is_err(ret))
	{
		cdb_close(cdb_ctx, dfp, SM_IO_CF_NONE);
		goto end;
	}
#endif

	/* open another instance */
	ret = CDB_OPEN_WRITE(cdb_ctx, ta_id, dfp, SM_IO_WREXCL, 1, &cdb_id);
	SM_TEST_E(SM_SUCCESS == ret);
	SM_TEST_E(cdb_id != NULL);

	/* write some stuff ... */
	ret = cdb_write(cdb_ctx, dfp, (uchar *) wbuf2, sizeof(wbuf2),
			&byteswritten);
	SM_TEST(SM_SUCCESS == ret);
	SM_TEST(byteswritten == sizeof(wbuf2));

	ret = cdb_close(cdb_ctx, dfp, SM_IO_CF_NONE);
	SM_TEST(SM_SUCCESS == ret);

	/* try to read */
	ret = cdb_open_read(cdb_ctx, ta_id, dfp);
	SM_TEST_E(SM_SUCCESS == ret);
	SM_TEST_E(dfp != NULL);

	ret = sm_io_read(dfp, rbuf, sizeof(rbuf), &bytesread);
	SM_TEST(SM_SUCCESS == ret);
	SM_TEST(bytesread == sizeof(rbuf));

	for (i = 0; i < sizeof(rbuf); i++)
	{
		SM_TEST(wbuf[i] == rbuf[i]);
		if (wbuf[i] != rbuf[i])
			break;
	}

	ret = cdb_close(cdb_ctx, dfp, SM_IO_CF_NONE);
	SM_TEST(SM_SUCCESS == ret);

	ret = cdb_unlink(cdb_ctx, ta_id);
	SM_TEST(SM_SUCCESS == ret);

	/* try to read 2nd instance */
	ret = cdb_open_read(cdb_ctx, (char *)sm_cstr_data(cdb_id), dfp);
	SM_TEST(SM_SUCCESS == ret);
	SM_TEST_E(dfp != NULL);

	ret = sm_io_read(dfp, rbuf, sizeof(rbuf), &bytesread);
	SM_TEST(SM_SUCCESS == ret);
	SM_TEST(bytesread == sizeof(rbuf));

	for (i = 0; i < sizeof(rbuf); i++)
	{
		SM_TEST(wbuf2[i] == rbuf[i]);
		if (wbuf2[i] != rbuf[i])
			break;
	}

	ret = cdb_close(cdb_ctx, dfp, SM_IO_CF_NONE);
	SM_TEST(SM_SUCCESS == ret);

	ret = cdb_unlink(cdb_ctx, (char *)sm_cstr_data(cdb_id));
	SM_TEST(SM_SUCCESS == ret);

#if TEST_CDB_BC
	sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT,
		(ulonglong_T) 2, 3);

	ret = CDB_OPEN_WRITE(cdb_ctx, ta_id, dfp, SM_IO_RDWRCRX, 0, &cdb_id);
	SM_TEST_E(SM_SUCCESS == ret);

	/* write some stuff ... */
	ret = cdb_write(cdb_ctx, dfp, (uchar *) wbuf, sizeof(wbuf),
			&byteswritten);
	SM_TEST(SM_SUCCESS == ret);
	SM_TEST(byteswritten == sizeof(wbuf));

	SM_TEST_E(cdb_id != NULL);
	r = stat(cdbf_path(dfp), &sb);
	SM_TEST(r < 0);
	SM_TEST(ENOENT == errno);

	ret = sm_io_dup(dfp);
	SM_TEST(SM_SUCCESS == ret);
	dfpr = dfp;

	ret = sm_io_seek(dfpr, 0, SM_IO_SEEK_SET);
	SM_TEST(SM_SUCCESS == ret);

	ret = sm_io_read(dfpr, rbuf, sizeof(rbuf), &bytesread);
	SM_TEST(SM_SUCCESS == ret);
	SM_TEST(bytesread == sizeof(rbuf));

	for (i = 0; i < sizeof(rbuf); i++)
	{
		SM_TEST(wbuf[i] == rbuf[i]);
		if (wbuf[i] != rbuf[i])
			break;
	}

#if 0
	ret = cdb_commit(cdb_ctx, dfp);
	SM_TEST(SM_SUCCESS == ret);

	SM_TEST_E(cdb_id != NULL);
	r = stat(cdbf_path(dfp), &sb);
	SM_TEST(0 == r);
#endif /* 0 */

	ret = cdb_close(cdb_ctx, dfp, SM_IO_CF_NONE);
	SM_TEST(SM_SUCCESS == ret);

	ret = cdb_close(cdb_ctx, dfpr, SM_IO_CF_NONE);
	SM_TEST(SM_SUCCESS == ret);
#endif /* TEST_CDB_BC */

  error:
#if !TEST_CDB_BC
  end:
#endif
	ret = cdb_end(cdb_ctx);
	SM_TEST(SM_SUCCESS == ret);

	return ret;
}

/*
**  USAGE -- usage message
**
**	Parameters:
**		prg -- program name
**
**	Returns:
**		none
*/

static void
usage(char *prg)
{
	sm_io_fprintf(smioerr, "usage: %s [options]\n"
		"perform CDB checks\n"
		"-b name  set base of CDB directory, default: empty\n"
		"         must be empty [= current directory] or end in '/'\n"
		, prg
		);
	return;
}

int
main(int argc, char *argv[])
{
	int c;
	char *base;

	base = "";
	while ((c = getopt(argc, argv, "b:")) != -1)
	{
		switch (c)
		{
		  case 'b':
			base = strdup(optarg);
			SM_TEST(base != NULL);
			if (NULL == base)
				return EX_OSERR;
			break;
		  default:
			usage(argv[0]);
			return EX_USAGE;
		}
	}

	sm_test_begin(argc, argv, "test cdb 0");
	cdb_test(base);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1