コード例 #1
0
/*{
** Name:	IIME_adAddTag	- Add a node of allocated memory to a tag.
**
** Description:
**	This routine is called when a new block of dynamic memory is being
**	allocated under a tag.  It is called by MEdoAlloc.  The job
**	of this routine is to store the allocated memory so that it
**	will be freed with the other blocks allocated under this tag when
**	MEtfree is called.
**
**	It works by checking the hash table for an METAGNODE for this tag.
**	If none is found, a new METAGNODE is allocated for this tag.
**	Then the block of memory is put on the QUEUE for the METAGNODE.
**
** Inputs:
**	tag		The tag under which this block of memory is
**			being allocated.
**
**	node		The block of memory being allocated.
**
** Side Effects:
**	This will take a node off freelist, and if necessary will allocate
**	dynamic memory.
**
** History:
**	5-dec-1989 (Joe)
**	    First Written
*/
VOID
IIME_atAddTag(
	i4	tag,
	ME_NODE	*node)
{
    register METAGNODE	**first;

# ifdef OS_THREADS_USED
    CS_synch_lock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */

    /*
    ** Note that first is a pointer to a pointer.
    ** The loop will cause a return from the routine if the tag already
    ** has an METAGNODE in the hash table.
    ** If the loop finishes, then first will point to the pointer
    ** that must contain the METAGNODE.
    */
    for (first = &(htab[tag%256]);
	 *first != NULL;
	 first = &((*first)->met_hash))
    {
	if ((*first)->met_tag == tag)
	{
	    (void)QUinsert((QUEUE *) node, (QUEUE *) (*first)->met_list.MElast);
# ifdef OS_THREADS_USED
	    CS_synch_unlock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
	    return;
	}
    }
    if (freelist == NULL)
    {
	register METAGNODE	*next;
	register int		i;

	freelist = (METAGNODE *)
			MEreqmem(0, sizeof(METAGNODE)*50, TRUE, NULL);
	for (i = 0, next = freelist; i < 49; i++)
	{
	    next->met_hash = next + 1;
	    next = next->met_hash;
	}
	next->met_hash = NULL;
    }
    *first = freelist;
    freelist = freelist->met_hash;
    (*first)->met_hash = NULL;
    (*first)->met_tag = tag;
    QUinit((QUEUE *)&((*first)->met_list));
    (void)QUinsert((QUEUE *) node, (QUEUE *) (*first)->met_list.MElast);
# ifdef OS_THREADS_USED
    CS_synch_unlock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
    return;
}
コード例 #2
0
GCADM_SCB *
gcadm_new_scb( i4 aid, PTR gca_cb )
{
   GCADM_SCB  *scb;

    scb = (GCADM_SCB *)(* GCADM_global.alloc_rtn )( sizeof( GCADM_SCB ) );
   
    if ( scb )
    {
	MEfill( sizeof( GCADM_SCB ), 0, scb);
	scb->buffer = (char *) (*GCADM_global.alloc_rtn)
			    ( GCADM_global.gcadm_buff_len );
   }
   
    if ( scb->buffer )
    {
	scb->aid  =  aid;
	scb->gca_cb = gca_cb;
	QUinit( &scb->q );
	QUinsert( &scb->q, GCADM_global.scb_q.q_prev); 
    }
    else
    {
	(*GCADM_global.dealloc_rtn)( (PTR)scb );
	scb = NULL;
    }

    return( scb );
}
コード例 #3
0
RETCODE SQL_API SQLSetConnectOption(
    SQLHDBC    hdbc,
    UWORD      fOption,
    SQLUINTEGER vParam)
{
    RETCODE rc, traceRet = 1;
    pDBC pdbc = (pDBC)hdbc;
    IISETCONNECTOPTION_PARAM *iiSetConnectOptionParam;

    ODBC_TRACE_ENTRY(ODBC_TR_TRACE, IITraceSQLSetConnectOption(hdbc,
        fOption, vParam), traceRet);

    if (!hdbc)
    {
        ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_INVALID_HANDLE));
        return SQL_INVALID_HANDLE;
    }
    /*
    **  If the driver isn't loaded yet, set a placeholder to do this 
    **  later.
    */
    if ( !IISetConnectOption )
    {
        iiSetConnectOptionParam = 
            (IISETCONNECTOPTION_PARAM *)MEreqmem(0, 
            sizeof(IISETCONNECTOPTION_PARAM), TRUE, NULL);
        QUinsert((QUEUE *)iiSetConnectOptionParam, &pdbc->setConnectOption_q);
        iiSetConnectOptionParam->ConnectionHandle = hdbc;
        iiSetConnectOptionParam->Option = fOption;
        iiSetConnectOptionParam->Value = vParam;
        pdbc->setConnectOption_count++;
        ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_SUCCESS));
        return SQL_SUCCESS;
    }
    else
    {
        resetErrorBuff(pdbc, SQL_HANDLE_DBC);

        rc = IISetConnectOption(
            pdbc->hdr.driverHandle,
            fOption,
            vParam);

        applyLock(SQL_HANDLE_DBC, pdbc);
        if (rc != SQL_SUCCESS)
        {
            pdbc->hdr.driverError = TRUE;
            pdbc->errHdr.rc = rc;
        }
        else if (fOption == SQL_ATTR_AUTOCOMMIT)
            pdbc->autocommit = TRUE;
        releaseLock(SQL_HANDLE_DBC, pdbc);
    }

    ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, rc));
    return rc;
}
コード例 #4
0
void
gcd_del_rcb( GCD_RCB *rcb )
{
    GCD_CCB	*ccb = rcb->ccb;
    u_i2	dflt_len = ccb->max_buff_len + (u_i2)GCD_global.nl_hdr_sz;

    /*
    ** If RCB has no buffer or has a default sized
    ** buffer, save RCB on free queue for re-use.
    ** Otherwise, free the RCB.
    */
    if ( ! rcb->buf_max )
	QUinsert( &rcb->q, GCD_global.rcb_q.q_prev );
    else  if ( rcb->buf_max == dflt_len )
	QUinsert( &rcb->q, ccb->rcb_q.q_prev );
    else
	gcd_free_rcb( rcb );

    return;
}
コード例 #5
0
GCD_CCB *
gcd_new_ccb( void )
{
    GCD_CCB	*ccb;

    if ( ! (ccb = (GCD_CCB *)QUremove( GCD_global.ccb_free.q_next )) )
	if ( (ccb = (GCD_CCB *)MEreqmem( 0, sizeof(GCD_CCB), FALSE, NULL )) )
	    ccb->id = GCD_global.ccb_total++;

    if ( ! ccb )
	gcu_erlog(0, GCD_global.language, E_GC4808_NO_MEMORY, NULL, 0, NULL);
    else
    {
	u_i4	id = ccb->id;

	MEfill( sizeof( GCD_CCB ), 0, (PTR)ccb );
	ccb->id = id;
	ccb->use_cnt = 1;
	ccb->max_buff_len = 1 << DAM_TL_PKT_MIN;
	ccb->tl.proto_lvl = DAM_TL_PROTO_1;
	ccb->xact.auto_mode = GCD_XACM_DBMS;
	ccb->api.env = NULL;
	QUinit( &ccb->q );
	QUinit( &ccb->rcb_q );
	QUinit( &ccb->gcc.send_q );
	QUinit( &ccb->msg.msg_q );
	QUinit( &ccb->msg.info_q );
	QUinit( &ccb->stmt.stmt_q );
	QUinit( &ccb->rqst.rqst_q );

	GCD_global.ccb_active++;
	QUinsert( &ccb->q, &GCD_global.ccb_q );

	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD new CCB (%d)\n", ccb->id, ccb->id );
    }

    return( ccb );
}
コード例 #6
0
static void 
gcadm_event( GCADM_RCB  *rcb )
{

   GCADM_SCB *scb=rcb->scb;

    if ( gcadm_active )
    {
	if ( GCADM_global.gcadm_trace_level >= 5 )
	    TRdisplay( "%4d   GCADM event: queueing event %s  \n",
		    scb->aid, events[ rcb->event ]);
	QUinsert( &rcb->q, GCADM_global.rcb_q.q_prev); 
	return;
    }

    gcadm_active = TRUE;
    gcadm_sm( rcb );

    while( ( rcb  = (GCADM_RCB  *)QUremove( GCADM_global.rcb_q.q_next )) )
    {
	if ( GCADM_global.gcadm_state != GCADM_ACTIVE )
	{
	    if ( GCADM_global.gcadm_trace_level >= 1 )
		TRdisplay( "%4d   GCADM event: ADM not active\n", -1 );
	    gcadm_free_rcb ( rcb );
	}
	else
	{
	    if( GCADM_global.gcadm_trace_level >= 5 )
		TRdisplay( "%4d   GCADM event: processing queued event %s \n",
			scb->aid, events[ rcb->event ]);
	    gcadm_sm( rcb );
	}
    }

    gcadm_active = FALSE;
    return;
}
コード例 #7
0
void
gcd_del_cib( GCD_CIB *cib )
{
    GCD_CAPS	*caps;
    char	buff[16];
    u_i2	i;

    GCD_global.cib_active--;

    MOulongout( 0, (u_i8)cib->id, sizeof( buff ), buff );
    MOdetach( GCD_MIB_DBMS, buff );

    while( (caps = (GCD_CAPS *)QUremove( cib->caps.q_next )) )
    {
	MEfree( caps->data );
	MEfree( (PTR)caps );
    }

    if ( cib->database )  MEfree( (PTR)cib->database );
    if ( cib->username )  MEfree( (PTR)cib->username );
    if ( cib->password )  MEfree( (PTR)cib->password );
    for( i = 0; i < cib->parm_cnt; i++ )  MEfree( (PTR)cib->parms[i].value );

    if ( GCD_global.gcd_trace_level >= 6 )
	TRdisplay( "%4d    GCD del CIB (%d)\n", -1, cib->id );

    if ( cib->parm_max < ARR_SIZE( GCD_global.cib_free ) )
	QUinsert( &cib->q, GCD_global.cib_free[ cib->parm_max ].q_prev );
    else
    {
	MEfree( (PTR)cib );
	GCD_global.cib_total--;
    }

    return;
}
コード例 #8
0
PTR
MEreqmem(
	u_i2	tag,
	SIZE_TYPE size,
	bool	zero,
	STATUS	*status)
{
    PTR	block=NULL;
    register ME_NODE *node;		/* the node to return */
    register ME_NODE *start;		/* for searching free list */
    register ME_NODE *this;		/* block to get node from */
    register ME_NODE *frag;		/* fragment block */
    
    ME_NODE 	*tmp;			/* not register for MEadd */
    SIZE_TYPE	nsize;			/* nsize node to obtain */
    SIZE_TYPE	fsize;			/* size of 'this' fragment block */
    SIZE_TYPE	newstuff;		/* size to add to process, or  0 */
    SIZE_TYPE	prev_actual;		/* rescan free list? */
    SIZE_TYPE	alloc_pages;
    CL_ERR_DESC	err_code;

    STATUS	MEstatus = OK;
    
    i_meuser += size;
    
    if (!size)
	MEstatus = ME_NO_ALLOC;
    
    if( !MEsetup )
        MEinitLists();
    
    /*
    **	Try to do the allocation.
    */
    if( MEstatus == OK )
    {
	nsize = SIZE_ROUND( size );
	/*
	** Get memory with malloc().
	*/
	if( MEadvice == ME_USER_ALLOC )
	{
	    if( (node = (ME_NODE *)malloc( nsize )) == NULL )
	    	MEstatus = ME_GONE;
	}
	/*
	** Get block from private free list.
	*/
	else
	{
# ifdef OS_THREADS_USED
	    CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */

	    /*
	    **  Look on free list for 1st block big enough
	    **  to hold request.  This linear search can be slow.
	    */
	    start = (ME_NODE *)&MEfreelist;
	    this = MEfreelist.MEfirst;
	    while ( this != NULL && this != start && this->MEsize < nsize )
		this = this->MEnext;
	    
	    if( this == NULL )
	        MEstatus = ME_CORRUPTED;
	    
	    /*
	    ** At this point, we are in one of three states:
	    ** 1)  Corrupted memory; MEstatus != OK
	    ** 2)  this is good node, this != start
	    ** 3)  No good node; this == start;
	    */
	    if ( MEstatus == OK )
	    {
		/*
		** If nothing on free list is big enough
		** get one or more standard blocks from system,
		** take what is needed and add remainder
		** to free list.
		*/
		if (this != start)
		{
		    /* take right off the free list */
		    newstuff = 0;
		}
		else	/* this == start */
		{
		    /*
		     * Expand the free list by calling getpages
		     * newstuff holds the number of pages needed
		     */
		    newstuff = (nsize + ME_MPAGESIZE-1)/ME_MPAGESIZE;
		    /* if first time allocation, get enough for MO overhead */
		    if ( (prev_actual = i_meactual) == (SIZE_TYPE) 0 )
			newstuff += 4;
# ifdef OS_THREADS_USED
	            CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    MEstatus = MEget_pages(ME_SPARSE_MASK, newstuff, NULL, 
			(PTR *)&tmp, &alloc_pages, &err_code);
# ifdef OS_THREADS_USED
	            CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    if (MEstatus == OK)
		    {
			/* now we need to find where to put this new memory
			   on the sorted free list - we search in reverse */
			tmp->MEsize = newstuff * ME_MPAGESIZE;
			this = MEfreelist.MElast;
			while (start != this && this != NULL &&
			       this > tmp)
			    this = this->MEprev;
			if (this != start && NEXT_NODE(this) == tmp)
			{
			    this->MEsize += tmp->MEsize;
			}
			else
			{
			    (void)QUinsert( (QUEUE *) tmp, (QUEUE *)this );
			    this = tmp;
			}
			if (this->MEnext != start &&
			    NEXT_NODE(this) == this->MEnext)
			{
			    this->MEsize += this->MEnext->MEsize;
			    (void)QUremove( (QUEUE *) this->MEnext);
			}
			/*
			** While the free list mutex was released, another
			** thread may have freed up a big enough piece of
			** memory for our needs, or may have extended the
			** free list.
			** If that's the case, research the free list;
			** we'll find either a right-sized node or 
			** the new memory we just added to the free list.
			*/
			if ( prev_actual != i_meactual )
			{
			    this = MEfreelist.MEfirst;
			    while ( this != NULL && this != start && this->MEsize < nsize )
				this = this->MEnext;
		
			    if( this == NULL )
				MEstatus = ME_CORRUPTED;
			}
		    }
		    else
			if (MEstatus == ME_OUT_OF_MEM)
			    MEstatus = ME_GONE;
		}

		/*
		** At this point, we can be in two states.
		** 1)  Corrupted memory, MEstatus != OK
		** 2)  'this' is an OK node from the free list.
		*/
		
		if ( MEstatus == OK )
		{
		    node = this;
		    
		    /*
		    ** if this is correct size or would
		    **   leave useless block in chain
		    **	just move block to allocated list
		    ** else
		    **	grab what is needed from 'this'
		    **	  block and then update 'this'
		    */
		    
		    fsize = node->MEsize - nsize;
		    if ( fsize <= sizeof(ME_NODE) )
		    {
			(void)QUremove( (QUEUE *) node );
			
			/* fudge size in node to eat leftover amount. */
			fsize = 0;
			nsize = node->MEsize;
		    }
		    else	/* make fragment block */
		    {
			/*
			** Make a leftover block after the
			** allocated space in node, in 'this'
			*/
			frag = (ME_NODE *)((char *) node + nsize );
			frag->MEsize = fsize;
			frag->MEtag = 0;
			
			/* remove node, add fragment to free list */
			(void)QUremove( (QUEUE *) node );
			MEstatus = MEfadd( frag, FALSE );
			
		    }  /* fragment left over */
		    /* Increment meactual while mutex held */
		    i_meactual += nsize;
		}  /* Got a node */
	    }  /* free list search OK */
# ifdef OS_THREADS_USED
	    CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
	}  /* ME_USER_ALLOC */
	
	/*
	** At this point we are in one of two states:
	** 1.  Corrupted, MEstatus != OK.
	** 2.  Have a 'node' to use, from freelist or malloc.
	**     The freelist is consistant, but the allocated list is
	**     not setup for the node. "nsize" is the actual size of "node".
	*/
	
	if( MEstatus == OK )
	{
	    /* splice into allocated object queue */
	    if (0 == tag)
	    {
# ifdef OS_THREADS_USED
	    	CS_synch_lock( &MElist_mutex );
# endif /* OS_THREADS_USED */
	    	(void)QUinsert( (QUEUE *) node, (QUEUE *) MElist.MElast );
# ifdef OS_THREADS_USED
		CS_synch_unlock( &MElist_mutex );
# endif /* OS_THREADS_USED */
	    }
	    else
	    {
		IIME_atAddTag(tag, node);
	    }
	    /* Set values in block to be returned */
	    node->MEtag = tag;
	    node->MEsize = nsize;
	    node->MEaskedfor = size;
	    
	    /* Fill in the returned pointer */
	    block = (PTR)((char *)node + sizeof(ME_NODE));
	    
	    if (zero)
		MEfill( (nsize - sizeof(ME_NODE)), 0, block);
	}  /* got node OK */
    }
    if (status != NULL)
	*status = MEstatus;
    if (MEstatus != OK)
	return((PTR)NULL);
    else
	return(block);
}
コード例 #9
0
II_EXTERN IIAPI_ENVHNDL *
IIapi_initAPI( II_LONG version, II_LONG timeout )
{
    IIAPI_ENVHNDL	*envHndl;
    IIAPI_ENVHNDL	*defEnvHndl;
    II_BOOL		first_init = FALSE;
    STATUS		status;
    char		*env;

    if ( ! IIapi_static )
    {
	/*
	** Perform global initializations which are
	** environment independent.  
	*/
	first_init = TRUE;

	if ( ! ( IIapi_static = (IIAPI_STATIC *)
		 MEreqmem( 0, sizeof( IIAPI_STATIC ), TRUE, &status ) ) )
	    return( NULL );

	QUinit( &IIapi_static->api_env_q );

	if ( MUi_semaphore( &IIapi_static->api_semaphore ) != OK )
	    goto muiFail;

	if ( MEtls_create( &IIapi_static->api_thread ) != OK )
	    goto metFail;

	/*
	** Initialize sub-systems.
	*/
	IIAPI_INITTRACE();
	IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_initAPI: initializing API.\n" );

	/*
	** Make sure II_SYSTEM or similar is set to provide useful feedback
	** rather than just failing in one of following subsystems.
	*/
	NMgtAt( SYSTEM_LOCATION_VARIABLE, &env );
	if ( env == NULL || *env == EOS )
	{
	    IIAPI_TRACE( IIAPI_TR_FATAL )
		( "IIapi_initAPI: error - %s not set.\n",
		  SYSTEM_LOCATION_VARIABLE );
	    goto adfFail;
	}
	
	IIapi_init_mib();
	if ( ! IIapi_initADF() )	goto adfFail;
	if ( ! IIapi_initGCA(timeout) )	goto gcaFail;

	/* Initialize the unicode collation values */
	IIapi_static->api_unicol_init = FALSE;
	IIapi_static->api_ucode_ctbl = NULL; 
	IIapi_static->api_ucode_cvtbl = NULL;

	/*
	** Create the default environment.
	*/
	if ( ! (IIapi_static->api_env_default = 
				(PTR)IIapi_createEnvHndl( IIAPI_VERSION_1 )) )
	    goto defFail;

	/* Spoken Language to use */

    	if( ( status = ERlangcode( (char *)NULL, 
				   &IIapi_static->api_slang ) != OK) )
    	{
	    IIAPI_TRACE( IIAPI_TR_ERROR )
		( "IIapi_initAPI: error initializing lang 0x%x\n", status );

	    return( NULL );
    	}

	/*
	** The SQL state machines are used by default prior to
	** IIapi_connect() being called, so make sure they are
	** initialized.
	*/
	if ( IIapi_sm_init( IIAPI_SMT_SQL ) != IIAPI_ST_SUCCESS )
	    goto envFail;
    }

    /*
    ** Now do environment specific initialization.
    */
    defEnvHndl = IIapi_defaultEnvHndl();

    if ( version == IIAPI_VERSION_1 )
    {
	/*
	** Version 1 initializers share the default
	** environment.  Keep track of the number of
	** initializers so that IIapi_termAPI() can
	** determine when to do global shutdown.
	*/
	envHndl = defEnvHndl;

	MUp_semaphore( &defEnvHndl->en_semaphore );
	defEnvHndl->en_initCount++;
	MUv_semaphore( &defEnvHndl->en_semaphore );
    }
    else
    {
	/*
	** Create a new environment for the initializer.
	** These environments are saved on the global
	** environment queue.  The caller may also make
	** API calls using the default environment handle, 
	** so increment the default environment handle
	** initialization count.
	*/
	if ( (envHndl = IIapi_createEnvHndl( version )) )
	{
	    MUp_semaphore( &IIapi_static->api_semaphore );
	    QUinsert( (QUEUE *)envHndl, &IIapi_static->api_env_q );
	    MUv_semaphore( &IIapi_static->api_semaphore );

	    MUp_semaphore( &defEnvHndl->en_semaphore );
	    defEnvHndl->en_initCount++;
	    MUv_semaphore( &defEnvHndl->en_semaphore );
	}
	else
	{
	    /*
	    ** We may need to undo the global initialization.
	    ** If not, the NULL environment handle will simply
	    ** be returned.
	    */
	    if ( first_init )  goto envFail;
	}
    }

    return( envHndl );

  envFail:
    IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default );

  defFail:
    IIapi_termGCA();

  gcaFail:
    IIapi_termADF();

  adfFail:
    IIAPI_TERMTRACE();
    MEtls_destroy( &IIapi_static->api_thread, NULL );

  metFail:
    MUr_semaphore( &IIapi_static->api_semaphore );

  muiFail:
    MEfree( (PTR)IIapi_static );
    IIapi_static = NULL;

    return( NULL );
}
コード例 #10
0
void
gcd_del_ccb( GCD_CCB *ccb )
{
    if ( ccb->use_cnt )  ccb->use_cnt--;

    if ( ccb->use_cnt )
    {
	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD del CCB (use count %d)\n", 
		       ccb->id, ccb->use_cnt );
    }
    else
    {
	GCD_RCB *rcb;
	GCD_SCB *scb;
	QUEUE	 *q;

	QUremove( &ccb->q );
	GCD_global.ccb_active--;
	if ( ccb->qry.crsr_name )  MEfree( (PTR)ccb->qry.crsr_name );
	if ( ccb->qry.schema_name )  MEfree( (PTR)ccb->qry.schema_name );
	if ( ccb->qry.proc_name )  MEfree( (PTR)ccb->qry.proc_name );
	if ( ccb->qry.qtxt_max )  MEfree( (PTR)ccb->qry.qtxt );
	if ( ccb->rqst.rqst_id0 )  MEfree( (PTR)ccb->rqst.rqst_id0 );
	if ( ccb->rqst.rqst_id1 )  MEfree( (PTR)ccb->rqst.rqst_id1 );
	if ( ccb->client_user )  MEfree( (PTR)ccb->client_user );
	if ( ccb->client_host )  MEfree( (PTR)ccb->client_host );
	if ( ccb->client_addr )  MEfree( (PTR)ccb->client_addr );
	gcd_free_qdata( &ccb->qry.svc_parms );
	gcd_free_qdata( &ccb->qry.qry_parms );
	gcd_free_qdata( &ccb->qry.all_parms );

	/*
	** Free control blocks and request queues.
	*/
	if ( ccb->cib )  gcd_del_cib( ccb->cib );

	if ( ccb->xact.savepoints )  gcd_release_sp( ccb, NULL );

	if ( ccb->msg.xoff_pcb )
	    gcd_del_pcb( (GCD_PCB *)ccb->msg.xoff_pcb );

	if ( ccb->gcc.abort_rcb )
	    gcd_del_rcb( (GCD_RCB *)ccb->gcc.abort_rcb );

	while( (scb = (GCD_SCB *)QUremove( ccb->stmt.stmt_q.q_next )) )
	{
	    gcd_free_qdata( &scb->column );
	    MEfree( (PTR)scb );
	}

	while( (rcb = (GCD_RCB *)QUremove( ccb->gcc.send_q.q_next )) )
	    gcd_del_rcb( rcb );

	while( (rcb = (GCD_RCB *)QUremove( ccb->msg.msg_q.q_next )) )
	    gcd_del_rcb( rcb );

	while( (rcb = (GCD_RCB *)QUremove( ccb->msg.info_q.q_next )) )
	    gcd_del_rcb( rcb );

	/* Free RCB must be physically freed */
	while( (rcb = (GCD_RCB *)QUremove( ccb->rcb_q.q_next )) )
	    gcd_free_rcb( rcb );

	while( (q = QUremove( ccb->rqst.rqst_q.q_next )) )
	    MEfree( (PTR)q );

	/*
	** Save CCB on free queue.
	*/
	QUinsert( &ccb->q, GCD_global.ccb_free.q_prev );

	if ( GCD_global.gcd_trace_level >= 5 )
	    TRdisplay( "%4d    GCD del CCB (%d)\n", ccb->id, ccb->id );
    }

    return;
}
コード例 #11
0
STATUS
MEfadd(
	ME_NODE	*block,
	i4 releasep)
{
    register ME_NODE *this;
    register ME_NODE *start;
    register ME_NODE *nextblk;	/* 1st address after end of 'block' */
    STATUS  MEstatus;

    MEstatus = OK;

    if ( block == NULL )
    {
	MEstatus = ME_00_PTR;
    }
    else if ( OUT_OF_DATASPACE(block) )
    {
	MEstatus = ME_OUT_OF_RANGE;
    }
    else
    {

	nextblk = NEXT_NODE(block);

	/*
	** The freelist IS sorted.  We might be able to take
	** advantage of this to speed up this linear search.
	** In practice the freelist is usually much
	** smaller than the allocated list, so it might not
	** really matter (daveb).
	*/

	/* adding inside existing freelist */
	start = (ME_NODE *)&MEfreelist;
	this = MEfreelist.MEfirst;

	while ( this != NULL && this != start && this < nextblk )
	    this = this->MEnext;

	if( this == NULL )
	    MEstatus = ME_CORRUPTED;

	/*
	** this->MEprev points to free node before 'block', the one
	** to free.  this points to the block in the free
	** list following 'block' to free.
	*/
	if ( MEstatus == OK )
	{
	    block->MEaskedfor = 0;
	    (void)QUinsert( (QUEUE *) block, (QUEUE *) this->MEprev );

	    /* Coalesce backwards until this is the start of the queue */
	    this = block;
	    while( this->MEprev != start &&
                 this->MEprev != this && NEXT_NODE(this->MEprev) == this )
	    {
		block = this->MEprev;
		block->MEsize += this->MEsize;
		(void)QUremove( (QUEUE *) this );
		this = block;
	    }

	    /* Coalesce forwards until the queue goes back to the start */
	    while( this->MEnext != start && NEXT_NODE(this) == this->MEnext )
	    {
		this->MEsize += this->MEnext->MEsize;
		(void)QUremove( (QUEUE *) this->MEnext );
	    }
	}
    }
			
    return(MEstatus);
}
コード例 #12
0
/*
** Name: GClanman_listen
** Description:
**	This is the listen thread for lanman.  It runs a syncronous accept()
**	on the listen socket.  When complete it Q's the completetion to
**	the completed event Q.  When accept completes, this thread returns.
**	A new one will be created when GClanman() gets the request to
**	repost the listen.
** History:
**	11-nov-93 (edg)
**	    created.
**	29-jun-2000 (somsa01)
**	    Use GCc_listen_port for the ncb_name.
**	16-mar-2001 (somsa01)
**	    Set node_id to ncb_callname.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Convert GCC completion queue mutex to a critical section
**          to improve performance (less overhead).
**	    Since _beginthreadex() is now used to start this thread,
**	    use _endthreadex() to end it.
*/
VOID
GClanman_listen( VOID *parms )
{
    GCC_P_PLIST		*parm_list = (GCC_P_PLIST *)parms;
    PCB			*pcb;
    STATUS		status = OK;
    REQUEST_Q		*rq;
    SECURITY_ATTRIBUTES	sa;

    iimksec (&sa);

    /*
    ** Initialize the listen node_id to NULL.
    */
    parm_list->function_parms.listen.node_id = NULL;

    /*
    ** Initialize fields of the Listen_Ncb
    */
    memset( &Listen_Ncb, 0, sizeof(NCB) );
    Listen_Ncb.ncb_buffer = parm_list->buffer_ptr;
    Listen_Ncb.ncb_length = (USHORT)parm_list->buffer_lng;
    Listen_Ncb.ncb_command = NCBLISTEN;
    Listen_Ncb.ncb_lana_num = lana_num;
    *Listen_Ncb.ncb_callname = (unsigned char)NULL;
    STmove( "*", ' ', NCBNAMSZ, Listen_Ncb.ncb_callname );
    *Listen_Ncb.ncb_name = (unsigned char)NULL;
    STcopy( GCc_listen_port, Listen_Ncb.ncb_name );


    /*
    ** Now we can do the NCBLISTEN request.  Block until it completes.
    */
    Netbios( &Listen_Ncb );
    if ( Listen_Ncb.ncb_retcode != NRC_GOODRET )
    {
	status = (int)Listen_Ncb.ncb_retcode;
	goto sys_err;
    }

    /*
    ** Allocate Protcol Control Block specific to this driver and put into
    ** parm list
    */
    pcb = (PCB *) malloc( sizeof(PCB) );
    if (pcb == NULL) 
    {
	status = errno;
	goto sys_err;
    }
    memset( pcb, 0, sizeof( *pcb ) );
    parm_list->pcb = (char *)pcb;

    /*
    ** Set node_id to the node name of the partner.
    */
    parm_list->function_parms.listen.node_id = STalloc(Listen_Ncb.ncb_callname);

    /*
    ** Now assign the pcb's send and receive NCB's the local session number
    ** returned by listen for further communications.
    */
    pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn = Listen_Ncb.ncb_lsn;

    /*
    ** Now create handles for the read and write event handles in the
    ** NCB.  These are created with manual reset as cautioned by the 
    ** programmer's guide so a ResetEvent MUST be done on them.
    */
    if ((pcb->s_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    {
        status = GetLastError();
	goto sys_err;
    }
    if ((pcb->r_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    {
        status = GetLastError();
	CloseHandle( pcb->s_ncb.ncb_event );
	pcb->s_ncb.ncb_event = NULL;
	goto sys_err;
    }

sys_err:
    if (status != OK) 
    {
        SETWIN32ERR(&parm_list->system_status, status, ER_create);
	parm_list->generic_status = GC_LISTEN_FAIL;
    }

    /*
    ** Now allocate a request q structure, stick it into complete q, and
    ** raise the GCC_COMPLETE event.
    */
    if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL )
    {
        rq->plist = parm_list;
	/*
	** Get critical section for completion Q.
	*/
	EnterCriticalSection( &GccCompleteQCritSect );

	/*
	** Now insert the completed request into the completed Q.
	*/
	QUinsert( &rq->req_q, &IIGCc_proto_threads.completed_head );

	/*
	** Exit/leave critical section for completion Q
	*/
	LeaveCriticalSection( &GccCompleteQCritSect );

	/*
	** raise the completion event to wake up GCexec.
	*/
	if ( !SetEvent( hAsyncEvents[GCC_COMPLETE] ) )
	{
	   /*
	   ** ruh roh.  We're screwed if this event can't be signaled.
	   */
	   status = GetLastError();
	   GCTRACE(1)("GClanman_listen, SetEvent error = %d\n", status );
	}

    }
    else
    {
        /*
	** ruh-roh.  MEreqmem failed.  Selious tlouble.  Not sure what to
	** do about it at this point since if it failed we can't notify
	** the completion routine.  For now, just return (exit thread)
	** which will probably have the effect of blocking all incoming
	** connections.
	*/
    }
    _endthreadex(0);
}
コード例 #13
0
/*
** Name: GClanman
** Description:
**	Main entry point for the window's NT lan manager protocol driver.  This
** 	driver is essentially just a dispatcher -- it runs in the primary
**	GCC thread and mostly just Q's things to do to the constantly running
**	aynchronous request thread.  It may also start a listen thread if
**	it is a LISTEN request.
**
**	The following functions are handled:
**	    GCC_OPEN	- call GClanman_open
**	    GCC_LISTEN  - start listen thread
**	    GCC_SEND    - Q request for asynch thread
**	    GCC_RECEIVE - Q request for asynch thread
**	    GCC_CONNECT - Q request for asynch thread
**	    GCC_DISCONN - Q request for asynch thread
** History:
**	11-Nov-93 (edg)
**	    Original.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Remove mutexing around calls to GCA service completion routine
**          as it is no longer necessary, since GCA is thread-safe...removes
**          calls to GCwaitCompletion + GCrestart. Should improve peformance.
**	    Convert CreateThread() to _beginthreadex() which is recommended
**	    when using C runtime.
*/
STATUS
GClanman( i4 function_code, GCC_P_PLIST * parm_list)
{
	STATUS          generror = 0;
	int             status = 0;
	int             tid;
	HANDLE          hThread;
    	REQUEST_Q 	*rq;
	SECURITY_ATTRIBUTES sa;

	iimksec (&sa);

	CLEAR_ERR(&parm_list->system_status);

	/*
	** set error based on function code and determine whether we got a
	** valid function.
	*/
	switch (function_code) {
	case GCC_OPEN:
		is_comm_svr = TRUE;
		GCTRACE(2) ("GClanman: Function = OPEN\n" );
		return GClanman_open( parm_list );

	case GCC_LISTEN:
		GCTRACE(2) ("GClanman: Function = LISTEN\n" );
		generror = GC_LISTEN_FAIL;
                /*
                ** For Lanman, the peer is always remote.
                */
                parm_list->options = 0;

		/*
		** Spawn off a thread to handle the listen request
		*/
		hThread = (HANDLE)_beginthreadex(&sa,
			       GC_STACK_SIZE,
			       (LPTHREAD_START_ROUTINE) GClanman_listen,
			       parm_list,
			       (unsigned long)NULL,
			       &tid);
		if (hThread) 
		{
			CloseHandle(hThread);
			return (OK);
		}
		status = errno;
		SETWIN32ERR(&parm_list->system_status, status, ER_create);
		goto err_exit;
		break;

	case GCC_CONNECT:
	    GCTRACE(2) ("GClanman: Function = CONNECT\n" );
	    generror = GC_CONNECT_FAIL;
	    break;
	case GCC_SEND:
	    GCTRACE(2) ("GClanman: Function = SEND\n" );
	    generror = GC_SEND_FAIL;
	    break;
	case GCC_RECEIVE:
	    GCTRACE(2) ("GClanman: Function = RECEIVE\n" );
	    generror = GC_RECEIVE_FAIL;
	    break;
	case GCC_DISCONNECT:
	    GCTRACE(2) ("GClanman: Function = DISCONNECT\n" );
	    generror = GC_DISCONNECT_FAIL;
	    break;

	default:
	    return FAIL;
	}			/* end switch */
	/*
	** CONNECT, SEND, RECEIVE and DISCONNECT are all dispatched
	** to the asynch thread.
   	** Now allocate a request q structure, stick it into incoming q,
   	** and raise the INCOMING REQUEST event.
   	*/
	GCTRACE(2)("GClanman: Q'ing request ...\n");

    	if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL )
    	{
            rq->plist = parm_list;
	    /*
	    ** get mutex for completion Q
	    */
	    GCTRACE(2)("GClanman: wait for input mutex ...\n");
	    WaitForSingleObject( hMutexThreadInQ, INFINITE );

	    /*
	    ** Now insert the completed request into the inconming Q.
	    */
	    GCTRACE(2)("GClanman: inserting incoming req ...\n");
	    QUinsert( &rq->req_q, &Tptr->incoming_head );

	    /*
	    ** release mutex for completion Q
	    */
	    GCTRACE(2)("GClanman: releasing Mutex incoming req ...\n");
	    ReleaseMutex( hMutexThreadInQ );

	    /*
	    ** raise the incoming event to wake up the thread.
	    */
	    GCTRACE(2)("GClanman: Setting event ...\n");
	    if ( !SetEvent( hEventThreadInQ ) )
	    {
	   	    status = GetLastError();
		    SETWIN32ERR(&parm_list->system_status, status, ER_sevent);
	   	    GCTRACE(1)("GClanman, SetEvent error = %d\n", 
		    		status );
	    }

	    return OK;

   	}
    	else
    	{
	        /*
		** MEreqmem failed
		*/
		SETWIN32ERR(&parm_list->system_status, errno, ER_alloc);
    	}

	/*
	 * * Drive the completion routine on error
	 */
err_exit:
	parm_list->generic_status = generror;
	(*parm_list->compl_exit) (parm_list->compl_id);
	return OK;
}
コード例 #14
0
SQLRETURN  SQL_API SQLSetEnvAttr (
    SQLHENV    EnvironmentHandle,
    SQLINTEGER Attribute,
    SQLPOINTER ValuePtr,
    SQLINTEGER StringLength)
{
    RETCODE rc, traceRet = 1;
    pENV penv = (pENV)EnvironmentHandle;
    IISETENVATTR_PARAM *iiSetEnvAttrParam;
    i4 value = (i4)(SCALARP)ValuePtr;

    if (block_init)
        ODBC_TRACE_ENTRY(ODBC_TR_TRACE, IITraceSQLSetEnvAttr(EnvironmentHandle,
            Attribute, ValuePtr, StringLength), traceRet);

    /*
    ** Connection pooling is set in the CLI before any drivers are loaded.
    */
    if (!EnvironmentHandle)
    {
        if (Attribute != SQL_ATTR_CONNECTION_POOLING)
        {
            rc = SQL_INVALID_HANDLE;
            goto exit_routine;
        }
        if (!block_init)
        {
            /*
            ** Initialize the CLI control block if connection pooling is 
            ** specified.
            */
            if (value == SQL_CP_ONE_PER_DRIVER || value == SQL_CP_ONE_PER_HENV)
            {
                IIodbc_initControlBlock();
                if (IIodbc_cb.timeout != -1)
                    IIodbc_createPoolThread();
                block_init = TRUE;
            }
        }
        
        if (value == SQL_CP_ONE_PER_DRIVER)
        {
            ODBC_EXEC_TRACE(ODBC_TR_TRACE)
                ("SQLSetEnvAttr: driver pool initialized\n");
            IIodbc_cb.pooling = DRIVER_POOL;
            QUinit(&IIodbc_cb.pool_q);
        }
        else if (value == SQL_CP_ONE_PER_HENV)
        {
            IIodbc_cb.pooling = HENV_POOL;
        }
        else if (value != SQL_CP_OFF)
        {
            /* 
            ** If the pooling arguments are invalid, only SQL_INVALID_HANDLE 
            ** can be returned because no environment handle exists.
            */
            rc = SQL_INVALID_HANDLE;
            goto exit_routine;
        } /* if (!initPool) */
        rc = SQL_SUCCESS;
        goto exit_routine;
    } /* if (!EnvironmentHandle) */
    
    
    if (Attribute == SQL_ATTR_CP_MATCH && value == SQL_CP_RELAXED_MATCH)
        penv->relaxed_match = TRUE;
    else
        penv->relaxed_match = FALSE;

    /*
    **  If the driver isn't loaded yet, set a placeholder to do this 
    **  later.
    */
    if ( !IISetEnvAttr )
    {
        if (Attribute == SQL_ATTR_ODBC_VERSION)
            penv->envAttrValue = ValuePtr;
        iiSetEnvAttrParam = 
        (IISETENVATTR_PARAM *)MEreqmem(0, sizeof(IISETENVATTR_PARAM), 
            TRUE, NULL);
        penv->setEnvAttr_count++;
        iiSetEnvAttrParam->Attribute = Attribute;
        iiSetEnvAttrParam->EnvironmentHandle = EnvironmentHandle;
        iiSetEnvAttrParam->ValuePtr = ValuePtr;
        iiSetEnvAttrParam->StringLength = StringLength;
        QUinsert((QUEUE *)iiSetEnvAttrParam, &penv->setEnvAttr_q);
        rc = SQL_SUCCESS;
        goto exit_routine;
    }

    if (penv->hdr.state < E2)
    {
        resetErrorBuff(penv, SQL_HANDLE_ENV);

        rc = IISetEnvAttr (
            penv->hdr.driverHandle,
            Attribute,
            ValuePtr,
            StringLength);
    }
    else
        rc = SQL_ERROR;

    applyLock(SQL_HANDLE_ENV, penv);
    if (rc != SQL_SUCCESS)
    {
        penv->hdr.driverError = TRUE;
        penv->errHdr.rc = rc;
    }
    releaseLock(SQL_HANDLE_ENV, penv);
    
exit_routine:
    ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, rc));
    return rc;
}
コード例 #15
0
RETCODE SQL_API SQLSetConnectAttr(
    SQLHDBC     hdbc,
    SQLINTEGER  fOption,
    SQLPOINTER  pValue,
    SQLINTEGER  StringLength)
{
    RETCODE rc, traceRet = 1;
    pDBC pdbc = (pDBC)hdbc;
    IISETCONNECTATTR_PARAM *iiSetConnectAttrParam;
    
    ODBC_TRACE_ENTRY(ODBC_TR_TRACE, IITraceSQLSetConnectAttr(hdbc, fOption,
       pValue, StringLength), traceRet);
    
    if (!hdbc)
    {
        ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_INVALID_HANDLE));
        return SQL_INVALID_HANDLE;
    }

    /*
    **  If the driver isn't loaded yet, set a placeholder to do this 
    **  later.
    */
    if (!IISetConnectAttr)
    {
        iiSetConnectAttrParam = 
            (IISETCONNECTATTR_PARAM *)MEreqmem(0, 
            sizeof(IISETCONNECTATTR_PARAM), TRUE, NULL);
        QUinsert((QUEUE *)iiSetConnectAttrParam, &pdbc->setConnectAttr_q);
        iiSetConnectAttrParam->ConnectionHandle = hdbc;
        iiSetConnectAttrParam->Attribute = fOption;
        iiSetConnectAttrParam->Value = pValue;
        iiSetConnectAttrParam->StringLength = StringLength;
        pdbc->setConnectAttr_count++;
        ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_SUCCESS));
        return SQL_SUCCESS;
    }
    else
    {
        resetErrorBuff( pdbc, SQL_HANDLE_DBC );
        rc = IISetConnectAttr(
            pdbc->hdr.driverHandle,
            fOption,
            pValue,
            StringLength);

        applyLock(SQL_HANDLE_DBC, pdbc);
        if (rc != SQL_SUCCESS)
        {
            pdbc->errHdr.rc = rc;
            pdbc->hdr.driverError = TRUE;
        }
        else if (fOption == SQL_ATTR_AUTOCOMMIT && StringLength == SQL_IS_INTEGER)
        {
            if (((ULONG)pValue) == SQL_AUTOCOMMIT_OFF)
                pdbc->autocommit = FALSE;
            else if (((ULONG)pValue) == SQL_AUTOCOMMIT_ON)
                pdbc->autocommit = TRUE;
        }
        releaseLock(SQL_HANDLE_DBC, pdbc);
    }
    ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, rc));
    return rc;
}
コード例 #16
0
main(int argc, char **argv)
{
    STATUS status = OK;
    VMS_STATUS vStatus;
    char srcbuf[NAME_FILE_SIZE];
    char dstbuf[NAME_FILE_SIZE];
    char delFile[NAME_FILE_SIZE];
    struct dsc$descriptor_s filename_d = 
        { sizeof (delFile) - 1,
            DSC$K_DTYPE_T,
            DSC$K_CLASS_S,
            delFile
        };
    FILE *srcFile = NULL;
    FILE *dstFile = NULL;
    FILE *nameFile = NULL;
    LOCATION loc;
    bool clusterArg = FALSE;
    bool unclusterArg = FALSE;
    bool writeOutput = FALSE;
    bool validSyntax;
    bool clustered = FALSE;
    bool v1DecryptErr = FALSE;
    bool rewrite = FALSE;
    bool isLogin = FALSE;
    i4   total_recs = 0;
    char local_host[MAX_LOC+CM_MAXATTRNAME];
    char config_host[MAX_LOC+CM_MAXATTRNAME];
    i2 i,j;
    i4 active_rec;
    i4 offset;
    char *onOff = NULL;
    bool srcOpened=FALSE;
    bool dstOpened=FALSE;
    bool printable = TRUE;
    GCN_QUEUE *gcn_q;
    GCN_QUEUE *merge_q;
    i4 rec_len = 0;
    QUEUE *q;
    u_i1  local_mask[ 8 ];        /* Must be 8 bytes */
    char name[MAX_LOC+CM_MAXATTRNAME];
    i4 count;
    char *p = NULL;
    i4 dcryptFail = 0;
    i2 pc;
    char *pv[ 3 ];
    GCN_DB_REC0 tmp_rec;
    SYSTIME timestamp;

    MEadvise(ME_INGRES_ALLOC);
    SIeqinit();
    GChostname( local_host, sizeof(local_host));
    STcopy (PMhost(), config_host);
    if (argc == 1)
       validSyntax = TRUE;
    /*
    ** Parse input arguments.
    */    
    for (i = 1; i < argc; i++)
    {
        validSyntax = FALSE;
        for (j = 0; j < argLen; j++)
        {
            if (!STncasecmp(arg[j],argv[i], STlength(argv[i])))
            {
                switch(j)
                {
                    case HELP1:
                    case HELP2:
                    case HELP3:
                    case HELP4:
                       usage();
                       break;

                    case VERBOSE:
                       validSyntax = TRUE;
                       verboseArg = TRUE;
                       break;

                    case CLUSTER:
                       validSyntax = TRUE;
                       clusterArg = TRUE;
                       writeOutput = TRUE;
                       break;

                    case UNCLUSTER:
                       validSyntax = TRUE;
                       unclusterArg = TRUE;
                       writeOutput = TRUE;
                       break;
                }
            } /* if (!STncasecmp(arg[j],argv[i], STlength(argv[i]))) */
            if (validSyntax)
                break;
        } /* for (j = 0; j < argLen; j++) */
        if (!validSyntax)
            break;
    } /* for (i = 1; i < argc; i++) */

    if (!validSyntax)
    {
        usage();
        PCexit(1);
    }

    if (clusterArg && unclusterArg)
    {
        SIprintf("Cannot specify both -c and -u\n\n");
            usage();
        PCexit(1);
    }

    if (verboseArg)
        SIprintf("Local host is %s\n", local_host);

    /*
    ** Generate key seeds for encoding and decoding.
    */
    STpolycat( 2, GCN_LOGIN_PREFIX, local_host, name );
    gcn_init_mask( name, sizeof( local_mask ), local_mask );

    QUinit(&gcn_qhead);
    QUinit(&merge_qhead);
    PMinit();

    /*
    ** See if this is a clustered installation.  If it is, 
    ** the node, login, and attribute files have no file extension.
    */
    if ( PMload( (LOCATION *)NULL, (PM_ERR_FUNC *)NULL ) != OK )
    {
        SIprintf("Error reading config.dat, exiting\n");
        goto cvt_exit;      
    }

    PMsetDefault( 0, SystemCfgPrefix );
    PMsetDefault( 1, config_host );
    PMsetDefault( 2, ERx("gcn") );

    status = PMget( ERx("!.cluster_mode"), &onOff);
    if (onOff && *onOff)
        ;
    else
        onOff = "OFF";

    if (verboseArg)
        SIprintf("Cluster mode is %s\n", onOff);

    if (!clusterArg && !unclusterArg)
        clustered = !STncasecmp(onOff, "ON", STlength(onOff));

    /*
    ** Rewrite the named GCN files.  For clustered installations, the
    ** node, login and attribute files have no hostname extension.
    */
    for ( i = 0; i < NBR_NAMED_FILES; i++ )
    {  
        /*
        ** Ticket files are simply deleted.
        */
        if (i == IILTICKET || i == IIRTICKET)
        {
            STprintf(delFile, "II_SYSTEM:[INGRES.FILES.NAME]II%s*;*", 
                named_file[i].file);
            if (verboseArg)
                SIprintf("Deleting %s\n", delFile);
            filename_d.dsc$w_length = STlength(delFile);
            vStatus = lib$delete_file(&filename_d,0,0,0,0,0,0,0,0,0);
            if (!vStatus & STS$M_SUCCESS)
                SIprintf("delete of %s failed, status is 0x%d\n", delFile,
                    vStatus);
            continue;
        }    
 
        rewrite = FALSE;
        if (!clusterArg && !unclusterArg)
            writeOutput = FALSE;
        if ( ( status = NMloc( FILES, PATH & FILENAME, 
            (char *)NULL, &loc ) ) != OK )
        {
            SIprintf("iicvtgcn: Could not find II_SYSTEM:[ingres.files]\n");
            goto cvt_exit;
        }
     
        LOfaddpath( &loc, "name", &loc );

        if (clustered || unclusterArg)
        {
            if (named_file[i].add_cluster_node)
                STprintf( srcbuf, "II%s_%s", named_file[i].file,config_host);
            else
                STprintf(srcbuf, "II%s", named_file[i].file);
        }
        else 
            STprintf( srcbuf, "II%s_%s", named_file[i].file,config_host);

        if (verboseArg)
            SIprintf("Opening %s for input\n", srcbuf);

        LOfstfile( srcbuf, &loc );

        /*
        ** Ignore non-existent files.
        */
        if ( LOexist( &loc ) != OK )
        {
            if (verboseArg)
                SIprintf("%s does not exist\n", srcbuf);
            continue;
        }
        /*
        ** Open the existing file as "regular" RACC.
        */
        status = SIfopen( &loc, "r", (i4)SI_RACC, sizeof( GCN_DB_REC0 ), 
            &srcFile );
        /*
        ** If the file exists but can't be opened, it's already optimized.
        */
        if (status == E_CL1904_SI_CANT_OPEN && ( LOexist( &loc ) == OK ) )
        {
            /*
            ** Open the existing file as "optimized" RACC.
            */
            status = SIfopen( &loc, "r", (i4)GCN_RACC_FILE, 
                sizeof( GCN_DB_REC0 ), &srcFile );
            if (status != OK)
            {
                SIprintf( "iicvtgcn: Error opening %s, status is %x\n",
                    srcbuf, status );
                continue;
            }
            if (verboseArg)
                SIprintf("%s is already optimized\n", srcbuf);
        }
        else if (status != OK)
        {
            SIprintf( "iicvtgcn: Error opening %s, status is %x\n",
                srcbuf, status );
            continue;
        }

        /*
        ** A successful open as SI_RACC means the file is not optimized.
        ** This file needs a rewrite.
        */
        else
        {
            if (verboseArg)
                SIprintf("Rewriting %s as optimized\n", srcbuf);
            writeOutput = TRUE;    
        }

        srcOpened = TRUE;

        while ( status == OK )
        {
            /*
            ** Read the source data and store in a queue for analysis.
            */
            status = SIread( srcFile, sizeof( GCN_DB_REC0 ),
                &count, (PTR)&tmp_rec );
            if ( status == ENDFILE )
                break;

            if ( status != OK )
            {
                SIprintf("iicvtgcn: Error reading %s, status is %x\n",
                    srcbuf, status);
                goto cvt_exit;
            }
            else if (tmp_rec.gcn_invalid && tmp_rec.gcn_tup_id != -1)
                continue;
            else
            {
                gcn_q = (GCN_QUEUE *)MEreqmem(0, sizeof(GCN_QUEUE),0,NULL);
                if (!gcn_q)
                {
                    SIprintf("iicvtgcn: Cannot allocate memory, exiting\n");
                    goto cvt_exit;
                }
                MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&gcn_q->buf);
                QUinsert(&gcn_q->q, &gcn_qhead);
                /*
                ** EOF record found.
                */
                if (gcn_q->buf.gcn_tup_id == -1)
                {
                    gcn_q->buf.gcn_l_uid = 0;
                    gcn_q->buf.gcn_uid[0] = '\0';
                    gcn_q->buf.gcn_l_obj = 0;
                    gcn_q->buf.gcn_obj[0] = '\0';
                    gcn_q->buf.gcn_l_val = 0;
                    gcn_q->buf.gcn_val[0] = '\0';
                    gcn_q->buf.gcn_invalid = TRUE;
                    break;
                }
            }
        } /* while ( status == OK ) */

        /*
        ** Decrypt passwords for IILOGIN files.  If any V1 records are found, 
        ** the IILOGIN file will need to be rewritten.
        */
        isLogin = FALSE;
        for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev)
        {
            gcn_q = (GCN_QUEUE *)q;

            /*
            ** EOF record found.
            */
            if (gcn_q->buf.gcn_tup_id == -1)
            {
                gcn_q->buf.gcn_invalid = TRUE;
                break;
            }

            if (i == IILOGIN)
            {
                isLogin = TRUE;
                MEcopy((PTR)&gcn_q->buf, sizeof(GCN_DB_REC0), (PTR)&tmp_rec);
                if (verboseArg)
                     SIprintf("\tEncoding vnode %s\n", gcn_q->buf.gcn_obj);

                if (unclusterArg)
                    status = gcn_recrypt( FALSE, local_mask, 
                        gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput);
                else if (clusterArg)
                    status = gcn_recrypt( TRUE, local_mask, 
                    gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput);
                else
                    status = gcn_recrypt( clustered, local_mask, 
                    gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput);

                if (status != OK)
                {
                    if (verboseArg)
                        SIprintf("Cannot decrypt password from " \
                            "vnode %s status %x\n", gcn_q->buf.gcn_obj,
                            status);
                    dcryptFail++;
                    MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), 
                        (PTR)&gcn_q->buf);
                    continue;                
                }
                if (v1DecryptErr)
                {
                    if (verboseArg)
                        SIprintf("Cannot decrypt password from " \
                            "vnode %s\n", gcn_q->buf.gcn_obj);
                    dcryptFail++;
                    MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), 
                        (PTR)&gcn_q->buf);
                    continue;
                }
            }  /* if (LOGIN) */

        } /* for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev) */
        
        if (dcryptFail && verboseArg && isLogin)
        {
            if (clustered || unclusterArg )
                SIprintf("\n%d vnode(s) could not be decrypted.\n" \
                    "Probably some login entries were created on " \
                    "another node.\nTry executing iicvtgcn on another " \
                    "node to merge the other node's entries.\n\n", dcryptFail);
            else
                SIprintf("\n%d vnode(s) could not be decrypted.\n" \
                    "Probably the login file was created on " \
                    "another host.\nTry executing iicvtgcn on " \
                    "a different host.\n\n", dcryptFail);
        }

        if (!writeOutput)
        {
            if (srcOpened)
                SIclose(srcFile);
            srcOpened = FALSE;
            cleanup_queues();
            continue;
        }
   
        /*
        ** Open the destination file with special GCN_RACC_FILE flag, for 
        ** optimized writes.
        */
        if (clustered || clusterArg) 
        {
            if (named_file[i].add_cluster_node)
                STprintf( dstbuf, "II%s_%s", named_file[i].file, local_host);
            else
                STprintf(dstbuf, "II%s", named_file[i].file);
        }
        else
            STprintf( dstbuf, "II%s_%s", named_file[i].file, local_host);

        if (clusterArg && !named_file[i].add_cluster_node)
            rewrite = TRUE;

        LOfstfile( dstbuf, &loc );

        if (rewrite)
        {
            status = SIfopen( &loc, "rw", (i4)GCN_RACC_FILE, 
                sizeof( GCN_DB_REC0 ), &dstFile );
            if ( status != OK )
            {
                status = SIfopen( &loc, "w", (i4)GCN_RACC_FILE, 
                    sizeof( GCN_DB_REC0 ), &dstFile );
                if (status == OK)
                {
                    SIclose( dstFile);
                    status = SIfopen( &loc, "rw", (i4)GCN_RACC_FILE, 
                        sizeof( GCN_DB_REC0 ), &dstFile );
                }
            }
        }
        else
            status = SIfopen( &loc, "w", (i4)GCN_RACC_FILE, 
                sizeof( GCN_DB_REC0 ), &dstFile );

        if ( status != OK )
        {
            SIprintf( "iicvtgcn: Error opening %s, status is %x\n",dstbuf,
                status );
            goto cvt_exit;
        }

        dstOpened = TRUE;

        if (verboseArg)
            SIprintf("%s %s\n", rewrite ? "Rewriting " : "Writing ", dstbuf);

        /*
        ** If this is a merge operation (-c), login, attribute or
        ** node files may change the location of EOF, since the
        ** file to be merged may have different records than
        ** the destination file. 
        ** Before merging, the output file is read and fed into a queue.
        ** Then each merge record is compared to each output record.
        ** If the entire records match, nothing is done. 
        ** If a global login record matches only the vnode name
        ** global or private records will be added if not present;
        ** otherwise, nothing is done.
        ** Node or attribute records may be added if only one field
        ** fails to match.
        */
        status = SIfseek(dstFile, (i4)0, SI_P_START);
        if (rewrite)
        {
            while ( status == OK )
            {
                /*
                ** Read the source data and store in a queue for analysis.
                */
                status = SIread( dstFile, sizeof( GCN_DB_REC0 ),
                    &count, (PTR)&tmp_rec );
                if ( status == ENDFILE )
                    break;

                if ( status != OK )
                {
                    SIprintf("iicvtgcn: Error reading %s, status is %x\n",
                        dstbuf, status);
                    goto cvt_exit;
                }
                else if (tmp_rec.gcn_invalid && tmp_rec.gcn_tup_id != -1)
                    continue;
                else
                {
                    merge_q = (GCN_QUEUE *)MEreqmem(0, sizeof(GCN_QUEUE),0,NULL);
                    if (!merge_q)
                    {
                        SIprintf("iicvtgcn: Cannot allocate memory, exiting\n");
                        goto cvt_exit;
                    }
                    MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), 
                        (PTR)&merge_q->buf);
                    QUinsert(&merge_q->q, &merge_qhead);
    
                    /*
                    ** EOF record found.
                    */
                    if (merge_q->buf.gcn_tup_id == -1)
                        break;
                }
                if ( status == ENDFILE )
                    break;

            } /* while ( status == OK ) */

            /*
            ** Go through the input queue.  Compare each record with
            ** the output (merge) queue.  If the record is invalid
            ** or doesn't match, it's ignored.
            */
            dcryptFail = 0;
            total_recs = 0;
            for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev)
            {
                SYSTIME     timestamp;

                gcn_q = (GCN_QUEUE *)q;
                if (gcn_q->buf.gcn_tup_id == -1)
                    break;
                if ( !gcn_merge_rec( gcn_q, isLogin ) )
                    continue;
                if (isLogin)
                {
                    /*
                    ** Login passwords get encrypted as V0 in a cluster
                    ** environment.
                    */
                    MEcopy((PTR)&gcn_q->buf, sizeof(GCN_DB_REC0), 
                        (PTR)&tmp_rec);
                    status = gcn_recrypt( TRUE, local_mask, 
                        gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput);

                    if (status != OK)
                    {
                        if (verboseArg)
                            SIprintf("Cannot decrypt password from " \
                                "vnode %s status %x\n", gcn_q->buf.gcn_obj,
                                status);
                        dcryptFail++;
                        MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), 
                            (PTR)&gcn_q->buf);
                        continue;                
                    }
                    if (v1DecryptErr)
                    {
                        if (verboseArg)
                            SIprintf("Cannot decrypt password from " \
                                "vnode %s\n", gcn_q->buf.gcn_obj);
                        dcryptFail++;
                        MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), 
                            (PTR)&gcn_q->buf);
                        continue;
                    }
                }
                merge_q = (GCN_QUEUE *)MEreqmem(0, sizeof(GCN_QUEUE),0,NULL);
                if (!merge_q)
                {
                    SIprintf("iicvtgcn: Cannot allocate memory, exiting\n");
                    goto cvt_exit;
                }

                MEcopy((PTR)&gcn_q->buf, sizeof(GCN_DB_REC0), 
                    (PTR)&merge_q->buf);
                total_recs++;
              
                QUinsert(&merge_q->q, &merge_qhead);
            }

            if (dcryptFail && verboseArg && isLogin)
            {
                if (clustered || unclusterArg )
                    SIprintf("\n%d vnode(s) could not be decrypted.\n" \
                        "Probably some login entries were created on " \
                        "another node.\nTry executing iicvtgcn on another " \
                        "node to merge the other node's entries.\n\n", 
                        dcryptFail);
                    else
                        SIprintf("\n%d vnode(s) could not be decrypted.\n" \
                            "Probably the login file was created on " \
                            "another host.\nTry executing iicvtgcn on " \
                            "a different host.\n\n", dcryptFail);
            }
            if (verboseArg)
                SIprintf("Total records merged: %d\n", total_recs);

            /*
            ** If no records to merge, clean up and continue.
            */
            if (!total_recs)
            {
                cleanup_queues();
                continue;
            }

            status = SIfseek(dstFile, (i4)0, SI_P_START);
            active_rec = 0;
            for (q = merge_qhead.q_prev; q != &merge_qhead; q = q->q_prev)
            {
                merge_q = (GCN_QUEUE *)q;
                if (verboseArg)
                   SIprintf("Rewriting %s record vnode %s val %s\n", 
                       !STcasecmp("*", merge_q->buf.gcn_uid) ? "global" : 
                       "private", merge_q->buf.gcn_obj, merge_q->buf.gcn_val);
                if (merge_q->buf.gcn_tup_id == -1)
                    continue;
                status = SIwrite(sizeof( GCN_DB_REC0 ), 
                    (char *)&merge_q->buf, &count, dstFile );
                if ( status != OK)
                {
                    SIprintf( "iicvtgcn: Failed to write file %s, " \
                        "status is %x\n", srcbuf, status );
                    goto cvt_exit;
                }
                active_rec++;
            }
            /*
            ** Write new EOF record.
            */
            tmp_rec.gcn_tup_id = -1;
            tmp_rec.gcn_l_uid = 0;
            tmp_rec.gcn_uid[0] = '\0';
            tmp_rec.gcn_l_obj = 0;
            tmp_rec.gcn_obj[0] = '\0';
            tmp_rec.gcn_l_val = 0;
            tmp_rec.gcn_val[0] = '\0';
            tmp_rec.gcn_invalid = TRUE;
            offset = active_rec * sizeof(GCN_DB_REC0);
            status = SIfseek(dstFile, (i4)offset, SI_P_START);
            status = SIwrite(sizeof( GCN_DB_REC0 ), (PTR)&tmp_rec, 
                &count, dstFile );
        }
        else
        {
            for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev)
            {
                gcn_q = (GCN_QUEUE *)q;
                gcn_q->buf.gcn_l_val = STlength(gcn_q->buf.gcn_val);
                if (verboseArg)
                   SIprintf("Writing %s record vnode %s val %s\n", 
                       !STcasecmp("*", gcn_q->buf.gcn_uid) ? "global" : 
                       "private", gcn_q->buf.gcn_obj, gcn_q->buf.gcn_val);
                status = SIwrite(sizeof( GCN_DB_REC0 ), (char *)&gcn_q->buf, 
                    &count, dstFile );
                if ( status != OK)
                {
                    SIprintf( "iicvtgcn: Failed to write file %s, " \
                        "status is %x\n", srcbuf, status );
                    goto cvt_exit;
                }
            }
        }  /* if (rewrite) */


        cleanup_queues();

        SIclose( srcFile );
        srcOpened = FALSE;
        SIclose( dstFile );
        dstOpened = FALSE;

    } /* for (i = 0; i < NBR_NAMED_FILES; i++ ) */

cvt_exit:

    cleanup_queues();

    if (srcOpened)
        SIclose(srcFile);
    if (dstOpened)
        SIclose(dstFile);
    PCexit( OK );
}