/****************************************************************
 *								*
 *	Copyright 2003, 2011 Fidelity Information Services, Inc	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#include "mdef.h"

#include "gtm_string.h"
#include "gtm_stdio.h"

#include "gdsroot.h"
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "buddy_list.h"
#include "jnl.h"
#include "hashtab_mname.h"	/* needed for muprec.h */
#include "hashtab_int4.h"	/* needed for muprec.h */
#include "hashtab_int8.h"	/* needed for muprec.h */
#include "muprec.h"
#include "gtmio.h"
#include "io.h"
#include "io_params.h"
#include "op.h"
#include "iosp.h"
#include "gtmmsg.h"
#include "gtm_rename.h"
#include "repl_instance.h"
#include "repl_msg.h"
#include "gtmsource.h"
#include "gtm_utf8.h"
#include "gtm_strings.h"

/* This function creates a file to hold either journal extract or broken transaction or lost transaction data.
 * The headerline of the file created will contain one of the following
 *
 *	Created by MUPIP JOURNAL -EXTRACT  --> EXTRACTLABEL<sp>EXTRACT
 *	Created by MUPIP JOURNAL -RECOVER  --> EXTRACTLABEL<sp>RECOVER
 *	Created by MUPIP JOURNAL -ROLLBACK --> EXTRACTLABEL<sp>ROLLBACK<sp>[PRIMARY|SECONDARY]<sp>INSTANCENAME
 *
 *	EXTRACTLABEL = NORMAL-EXTRACT-LABEL | DETAILED-EXTRACT-LABEL	// see muprec.h
 *	<sp> : Space
 *	RECOVER, EXTRACT, ROLLBACK, PRIMARY, SECONDARY : literal strings that appear as is.
 *	INSTANCENAME : Name of the replication instance
 */

GBLREF 	mur_gbls_t	murgbl;
GBLREF	mur_opt_struct	mur_options;
GBLREF	jnlpool_addrs	jnlpool;
GBLREF	int		(*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);

error_def(ERR_FILENOTCREATE);
error_def(ERR_FILECREATE);

int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat)
{
	fi_type			*file_info;
	char			*ptr, rename_fn[MAX_FN_LEN];
	int			rename_fn_len, base_len, fn_exten_size, extrlen, tmplen;
	uint4			status;
	mval			op_val, op_pars;
	boolean_t		is_stdout;	/* Output will go STDOUT? */
	static readonly	char 	*fn_exten[] = {EXT_MJF, EXT_BROKEN, EXT_LOST};
	static readonly	char 	*ext_file_type[] = {STR_JNLEXTR, STR_BRKNEXTR, STR_LOSTEXTR};
	static readonly unsigned char		open_params_list[]=
	{
		(unsigned char)iop_m,
		(unsigned char)iop_newversion,
		(unsigned char)iop_noreadonly,
		(unsigned char)iop_nowrap,
		(unsigned char)iop_stream,
		(unsigned char)iop_eol
	};

	assert(GOOD_TN == recstat || BROKEN_TN == recstat || LOST_TN == recstat);
	assert(0 == GOOD_TN);
	assert(1 == BROKEN_TN);
	assert(2 == LOST_TN);
	assert(GOOD_TN != recstat || mur_options.extr[GOOD_TN]);
	/* Argument journal -extract=-stdout ? */
	is_stdout = mur_options.extr_fn[recstat]
		&& (0 == STRNCASECMP(mur_options.extr_fn[recstat], JNL_STDO_EXTR, SIZEOF(JNL_STDO_EXTR)));
	/* If we need to write to stdout, we can bypass file renaming stuff */
	if(!is_stdout)
	{
		ptr = (char *)&jctl->jnl_fn[jctl->jnl_fn_len];
		while (DOT != *ptr)	/* we know journal file name alway has a DOT */
			ptr--;
		base_len = (int)(ptr - (char *)&jctl->jnl_fn[0]);
		file_info = murgbl.file_info[recstat] = (void *)malloc(SIZEOF(fi_type));
		if (0 == mur_options.extr_fn_len[recstat])
		{
			mur_options.extr_fn[recstat] = malloc(MAX_FN_LEN);
			mur_options.extr_fn_len[recstat] = base_len;
			memcpy(mur_options.extr_fn[recstat], jctl->jnl_fn, base_len);
			fn_exten_size = STRLEN(fn_exten[recstat]);
			memcpy(mur_options.extr_fn[recstat] + base_len, fn_exten[recstat], fn_exten_size);
			mur_options.extr_fn_len[recstat] += fn_exten_size;
		}
		file_info->fn_len = mur_options.extr_fn_len[recstat];
		file_info->fn = mur_options.extr_fn[recstat];
		if (RENAME_FAILED == rename_file_if_exists(file_info->fn, file_info->fn_len, rename_fn, &rename_fn_len, &status))
			return status;
		op_pars.mvtype = MV_STR;
		op_pars.str.len = SIZEOF(open_params_list);
		op_pars.str.addr = (char *)open_params_list;
		op_val.mvtype = MV_STR;
		op_val.str.len = file_info->fn_len;
		op_val.str.addr = (char *)file_info->fn;
		if ((status = (*op_open_ptr)(&op_val, &op_pars, 0, NULL)) == 0)
		{
			gtm_putmsg(VARLSTCNT(5) ERR_FILENOTCREATE, 2, file_info->fn_len, file_info->fn, errno);
			return ERR_FILENOTCREATE;
		}
	}
	/* Write file version info for the file created here. See C9B08-001729 */
	if (!mur_options.detail)
	{
		MEMCPY_LIT(murgbl.extr_buff, JNL_EXTR_LABEL);
		extrlen = STR_LIT_LEN(JNL_EXTR_LABEL);
	} else
	{
		MEMCPY_LIT(murgbl.extr_buff, JNL_DET_EXTR_LABEL);
		extrlen = STR_LIT_LEN(JNL_DET_EXTR_LABEL);
	}
	if (LOST_TN == recstat)
	{
		if (mur_options.update)
		{
			if (mur_options.rollback)
				ptr = " ROLLBACK";
			else
				ptr = " RECOVER";
		} else
			ptr = " EXTRACT";
		tmplen = STRLEN(ptr);
		memcpy(&murgbl.extr_buff[extrlen], ptr, tmplen);
		extrlen += tmplen;
		if (mur_options.rollback)
		{
			if (mur_options.fetchresync_port && murgbl.was_rootprimary)
				ptr = " PRIMARY ";
			else
				ptr = " SECONDARY ";
			tmplen = STRLEN(ptr);
			memcpy(&murgbl.extr_buff[extrlen], ptr, tmplen);
			extrlen += tmplen;
			assert(NULL != jnlpool.repl_inst_filehdr);
			ptr = (char *)&jnlpool.repl_inst_filehdr->inst_info.this_instname[0];
			tmplen = STRLEN(ptr);
			memcpy(&murgbl.extr_buff[extrlen], ptr, tmplen);
			extrlen += tmplen;
		}
	}
	if (gtm_utf8_mode)
	{
		murgbl.extr_buff[extrlen++] = ' ';
		MEMCPY_LIT(&murgbl.extr_buff[extrlen], UTF8_NAME);
		extrlen += STR_LIT_LEN(UTF8_NAME);
	}
	murgbl.extr_buff[extrlen++] = '\\';
	jnlext_write((is_stdout ? NULL : file_info), murgbl.extr_buff, extrlen);
	if (!is_stdout) /* We wrote to stdout so it doesn't make a sense to print a message about file creation. */
		gtm_putmsg(VARLSTCNT(6) ERR_FILECREATE, 4, LEN_AND_STR(ext_file_type[recstat]), file_info->fn_len, file_info->fn);
	return SS_NORMAL;
}
