int freeRuleExecInfoInternals(ruleExecInfo_t *rs, int freeSpeialStructFlag) { if (rs->msParamArray != NULL && (freeSpeialStructFlag & FREE_MS_PARAM) > 0) { clearMsParamArray (rs->msParamArray, 1); free (rs->msParamArray); } if (rs->doinp != NULL && (freeSpeialStructFlag & FREE_DOINP) > 0) { clearDataObjInp (rs->doinp); free (rs->doinp); } if (rs->doi != NULL) freeAllDataObjInfo(rs->doi); if (rs->rgi != NULL) freeRescGrpInfo(rs->rgi); if (rs->uoic != NULL) freeUserInfo(rs->uoic); if (rs->uoip != NULL) freeUserInfo(rs->uoip); if (rs->coi != NULL) freeCollInfo(rs->coi); #if 0 /* XXXXX deplicate rgio */ if (rs->rgio != NULL) freeRescGrpInfo(rs->rgio); #endif if (rs->uoio != NULL) freeUserInfo(rs->uoio); if (rs->condInputData != NULL) freeKeyValPairStruct(rs->condInputData); if (rs->next != NULL) freeRuleExecInfoStruct(rs->next, freeSpeialStructFlag); return(0); }
/** * \fn rcExecMyRule( rcComm_t *conn, execMyRuleInp_t *execMyRuleInp, msParamArray_t **outParamArray ) * * \brief Execute my rule. * * \user client * * \ingroup rules * * \since 1.0 * * * \remark none * * \note none * * \param[in] conn - A rcComm_t connection handle to the server. * \param[in] execMyRuleInp * \param[out] outParamArray * * \return integer * \retval 0 on success. * \sideeffect none * \pre none * \post none * \sa none **/ int rcExecMyRule( rcComm_t *conn, execMyRuleInp_t *execMyRuleInp, msParamArray_t **outParamArray ) { int status = procApiRequest( conn, EXEC_MY_RULE_AN, execMyRuleInp, NULL, ( void ** )outParamArray, NULL ); while ( status == SYS_SVR_TO_CLI_MSI_REQUEST ) { /* it is a server request */ msParam_t *myParam = NULL, *putParam = NULL; if ( ( myParam = putParam = getMsParamByLabel( *outParamArray, CL_PUT_ACTION ) ) || ( myParam = getMsParamByLabel( *outParamArray, CL_GET_ACTION ) ) ) { //putParam is non-null if it's a put, null if it's a get dataObjInp_t * dataObjInp = ( dataObjInp_t * ) myParam->inOutStruct; char * locFilePath; char myDir[MAX_NAME_LEN], myFile[MAX_NAME_LEN]; // locFilePath should be the return of getValByKey if it exists, // otherwise use the filename from splitPathByKey if ( ( locFilePath = getValByKey( &dataObjInp->condInput, LOCAL_PATH_KW ) ) || ( ( status = splitPathByKey( dataObjInp->objPath, myDir, MAX_NAME_LEN, myFile, MAX_NAME_LEN, '/' ) ) >= 0 && ( locFilePath = ( char * ) myFile ) ) ) { status = putParam ? rcDataObjPut( conn, dataObjInp, locFilePath ) : rcDataObjGet( conn, dataObjInp, locFilePath ); rcOprComplete( conn, status ); } else { rodsLogError( LOG_ERROR, status, "rcExecMyRule: splitPathByKey for %s error", dataObjInp->objPath ); rcOprComplete( conn, USER_FILE_DOES_NOT_EXIST ); } clearKeyVal( &dataObjInp->condInput ); } else { rcOprComplete( conn, SYS_SVR_TO_CLI_MSI_NO_EXIST ); } /* free outParamArray */ clearMsParamArray( *outParamArray, 1 ); free( *outParamArray ); *outParamArray = NULL; /* read the reply from the earlier call */ status = branchReadAndProcApiReply( conn, EXEC_MY_RULE_AN, ( void ** )outParamArray, NULL ); if ( status < 0 ) { rodsLogError( LOG_DEBUG, status, "rcExecMyRule: readAndProcApiReply failed. status = %d", status ); } } return status; }
/* * Set retOutParam to 1 if you need to retrieve the output parameters from inMsParamArray and 0 if not */ Res *parseAndComputeExpressionAdapter( char *inAction, msParamArray_t *inMsParamArray, int retOutParams, ruleExecInfo_t *rei, int reiSaveFlag, Region *r ) { // JMC - backport 4540 /* set clearDelayed to 0 so that nested calls to this function do not call clearDelay() */ int recclearDelayed = ruleEngineConfig.clearDelayed; ruleEngineConfig.clearDelayed = 0; int freeRei = 0; if ( rei == NULL ) { rei = ( ruleExecInfo_t * ) malloc( sizeof( ruleExecInfo_t ) ); memset( rei, 0, sizeof( ruleExecInfo_t ) ); freeRei = 1; } rei->status = 0; Env *env = defaultEnv( r ); /* retrieve generated data here as it may be overridden by convertMsParamArrayToEnv */ Res *res; rError_t errmsgBuf; errmsgBuf.errMsg = NULL; errmsgBuf.len = 0; if ( inMsParamArray != NULL ) { convertMsParamArrayToEnv( inMsParamArray, env, r ); deleteFromHashTable(env->current, "ruleExecOut"); } res = parseAndComputeExpression( inAction, env, rei, reiSaveFlag, &errmsgBuf, r ); if ( retOutParams ) { // JMC - backport 4540 if ( inMsParamArray != NULL ) { clearMsParamArray( inMsParamArray, 0 ); convertEnvToMsParamArray( inMsParamArray, env, &errmsgBuf, r ); } } /* deleteEnv(env, 3); */ if ( getNodeType( res ) == N_ERROR && !freeRei ) { logErrMsg( &errmsgBuf, &rei->rsComm->rError ); rei->status = RES_ERR_CODE( res ); } freeRErrorContent( &errmsgBuf ); if ( freeRei ) { free( rei ); } if ( recclearDelayed ) { clearDelayed(); } ruleEngineConfig.clearDelayed = recclearDelayed; return res; }
/** * \cond oldruleengine * \fn remoteExec(msParam_t *mPD, msParam_t *mPA, msParam_t *mPB, msParam_t *mPC, ruleExecInfo_t *rei) * * \brief A set of statements to be remotely executed * * \module core * * \since pre-2.1 * * \author Arcot Rajasekar * \date 2008 * * \note This micoservice takes a set of microservices that need to be executed at a * remote iRODS server. The execution is done immediately and synchronously with * the result returning back from the call. * * \usage See clients/icommands/test/rules3.0/ * * \param[in] mPD - a msParam of type STR_MS_T which is a host name of the server where the body need to be executed. * \param[in] mPA - a msParam of type STR_MS_T which is a delayCondition about when to execute the body. * \param[in] mPB - a msParam of type STR_MS_T which is a body. A statement list - micro-services and ruleNames separated by ## * \param[in] mPC - a msParam of type STR_MS_T which is arecoverBody. A statement list - micro-services and ruleNames separated by ## * \param[in,out] rei - The RuleExecInfo structure that is automatically * handled by the rule engine. The user does not include rei as a * parameter in the rule invocation. * * \DolVarDependence none * \DolVarModified none * \iCatAttrDependence none * \iCatAttrModified none * \sideeffect none * * \return integer * \retval 0 on success * \pre none * \post none * \sa none * \endcond **/ int remoteExec( msParam_t *mPD, msParam_t *mPA, msParam_t *mPB, msParam_t *mPC, ruleExecInfo_t *rei ) { int i; execMyRuleInp_t execMyRuleInp; msParamArray_t *tmpParamArray, *aParamArray; msParamArray_t *outParamArray = NULL; char tmpStr[LONG_NAME_LEN]; char tmpStr1[LONG_NAME_LEN]; /* char actionCall[MAX_ACTION_SIZE]; char recoveryActionCall[MAX_ACTION_SIZE]; char delayCondition[MAX_ACTION_SIZE]; char hostName[MAX_ACTION_SIZE]; rstrcpy(hostName, (char *) mPD->inOutStruct,MAX_ACTION_SIZE); rstrcpy(delayCondition, (char *) mPA->inOutStruct,MAX_ACTION_SIZE); rstrcpy(actionCall, (char *) mPB->inOutStruct,MAX_ACTION_SIZE); rstrcpy(recoveryActionCall, (char *) mPC->inOutStruct,MAX_ACTION_SIZE); i = _remoteExec(actionCall, recoveryActionCall, delayCondition, hostName, rei); */ memset( &execMyRuleInp, 0, sizeof( execMyRuleInp ) ); execMyRuleInp.condInput.len = 0; rstrcpy( execMyRuleInp.outParamDesc, ALL_MS_PARAM_KW, LONG_NAME_LEN ); /* rstrcpy (execMyRuleInp.addr.hostAddr, mPD->inOutStruct, LONG_NAME_LEN);*/ rstrcpy( tmpStr, ( char * ) mPD->inOutStruct, LONG_NAME_LEN ); i = evaluateExpression( tmpStr, tmpStr1, rei ); if ( i < 0 ) { return( i ); } parseHostAddrStr( tmpStr1, &execMyRuleInp.addr ); if ( strlen( ( char* )mPC->inOutStruct ) != 0 ) { snprintf( execMyRuleInp.myRule, META_STR_LEN, "remExec||%s|%s", ( char* )mPB->inOutStruct, ( char* )mPC->inOutStruct ); } else { snprintf( execMyRuleInp.myRule, META_STR_LEN, "remExec{%s}", ( char* )mPB->inOutStruct ); } addKeyVal( &execMyRuleInp.condInput, "execCondition", ( char * ) mPA->inOutStruct ); tmpParamArray = ( msParamArray_t * ) malloc( sizeof( msParamArray_t ) ); memset( tmpParamArray, 0, sizeof( msParamArray_t ) ); i = replMsParamArray( rei->msParamArray, tmpParamArray ); if ( i < 0 ) { free( tmpParamArray ); return( i ); } aParamArray = rei->msParamArray; rei->msParamArray = tmpParamArray; execMyRuleInp.inpParamArray = rei->msParamArray; i = rsExecMyRule( rei->rsComm, &execMyRuleInp, &outParamArray ); carryOverMsParam( outParamArray, aParamArray ); rei->msParamArray = aParamArray; clearMsParamArray( tmpParamArray, 0 ); free( tmpParamArray ); return( i ); }
int applyRuleForPostProcForRead( rsComm_t *rsComm, bytesBuf_t *dataObjReadOutBBuf, char *objPath ) { if ( ReadWriteRuleState != ON_STATE ) { return 0; } ruleExecInfo_t rei2; memset( ( char* )&rei2, 0, sizeof( ruleExecInfo_t ) ); msParamArray_t msParamArray; memset( ( char* )&msParamArray, 0, sizeof( msParamArray_t ) ); if ( rsComm != NULL ) { rei2.rsComm = rsComm; rei2.uoic = &rsComm->clientUser; rei2.uoip = &rsComm->proxyUser; } rei2.doi = ( dataObjInfo_t* )mallocAndZero( sizeof( dataObjInfo_t ) ); snprintf( rei2.doi->objPath, sizeof( rei2.doi->objPath ), "%s", objPath ); memset( &msParamArray, 0, sizeof( msParamArray ) ); int * myInOutStruct = ( int* )malloc( sizeof( int ) ); *myInOutStruct = dataObjReadOutBBuf->len; addMsParamToArray( &msParamArray, "*ReadBuf", BUF_LEN_MS_T, myInOutStruct, dataObjReadOutBBuf, 0 ); int status = applyRule( "acPostProcForDataObjRead(*ReadBuf)", &msParamArray, &rei2, NO_SAVE_REI ); free( rei2.doi ); if ( status < 0 ) { if ( rei2.status < 0 ) { status = rei2.status; } rodsLog( LOG_ERROR, "rsDataObjRead: acPostProcForDataObjRead error=%d", status ); clearMsParamArray( &msParamArray, 0 ); return status; } clearMsParamArray( &msParamArray, 0 ); return 0; }
int clearMsparamInRei (ruleExecInfo_t *rei) { if (rei == NULL || rei->msParamArray == NULL) { return (0); } /* need to use 0 on delStruct flag or core dump in when called by * finalizeMsParamNew */ clearMsParamArray (rei->msParamArray, 0); free (rei->msParamArray); rei->msParamArray = NULL; return (0); }
/// =-=-=-=-=-=-=- /// @brief function which manages the TLS and Auth negotiations with the client error client_server_negotiation_for_server( irods::network_object_ptr _ptr, std::string& _result ) { // =-=-=-=-=-=-=- // manufacture an rei for the applyRule ruleExecInfo_t rei; memset( ( char* )&rei, 0, sizeof( ruleExecInfo_t ) ); // =-=-=-=-=-=-=- // if it is, then call the pre PEP and get the result msParamArray_t params; memset( ¶ms, 0, sizeof( params ) ); int status = applyRuleUpdateParams( "acPreConnect(*OUT)", ¶ms, &rei, NO_SAVE_REI ); if ( 0 != status ) { return ERROR( status, "failed in call to applyRuleUpdateParams" ); } // =-=-=-=-=-=-=- // extract the value from the outgoing param to pass out to the operation char* rule_result_ptr = 0; msParam_t* out_ms_param = getMsParamByLabel( ¶ms, "*OUT" ); if ( out_ms_param ) { rule_result_ptr = reinterpret_cast< char* >( out_ms_param->inOutStruct ); } else { return ERROR( SYS_INVALID_INPUT_PARAM, "null out parameter" ); } if ( !rule_result_ptr ) { return ERROR( SYS_INVALID_INPUT_PARAM, "rule_result is null" ); } std::string rule_result( rule_result_ptr ); clearMsParamArray( ¶ms, 0 ); // =-=-=-=-=-=-=- // check to see if a negoation was requested if ( !do_client_server_negotiation_for_server() ) { // =-=-=-=-=-=-=- // if it was not but we require SSL then error out if ( CS_NEG_REQUIRE == rule_result ) { std::stringstream msg; msg << "SSL is required by the server but not requested by the client"; return ERROR( SYS_INVALID_INPUT_PARAM, msg.str() ); } else { // =-=-=-=-=-=-=- // a negotiation was not requested, bail return SUCCESS(); } } // =-=-=-=-=-=-=- // pass the PEP result to the client, send CS_NEG_SVR_1_MSG irods::cs_neg_t cs_neg; cs_neg.status_ = CS_NEG_STATUS_SUCCESS; snprintf( cs_neg.result_, sizeof( cs_neg.result_ ), "%s", rule_result.c_str() ); error err = send_client_server_negotiation_message( _ptr, cs_neg ); if ( !err.ok() ) { std::stringstream msg; msg << "failed with PEP value of [" << rule_result << "]"; return PASSMSG( msg.str(), err ); } // =-=-=-=-=-=-=- // get the response from CS_NEG_CLI_1_MSG boost::shared_ptr< cs_neg_t > read_cs_neg; err = read_client_server_negotiation_message( _ptr, read_cs_neg ); if ( !err.ok() ) { return PASS( err ); } // =-=-=-=-=-=-=- // get the result from the key val pair if ( strlen( read_cs_neg->result_ ) != 0 ) { irods::kvp_map_t kvp; err = irods::parse_kvp_string( read_cs_neg->result_, kvp ); if ( err.ok() ) { // =-=-=-=-=-=-=- // extract the signed SID if ( kvp.find( CS_NEG_SID_KW ) != kvp.end() ) { std::string svr_sid = kvp[ CS_NEG_SID_KW ]; if ( !svr_sid.empty() ) { // =-=-=-=-=-=-=- // get our SID to compare server_properties& props = server_properties::getInstance(); err = props.capture_if_needed(); if ( !err.ok() ) { return PASS( err ); } // =-=-=-=-=-=-=- // check SID against our SIDs err = check_sent_sid( props, svr_sid ); if ( !err.ok() ) { rodsLog( LOG_DEBUG, "[%s]", PASS( err ).status() ); } else { // =-=-=-=-=-=-=- // store property that states this is an // Agent-Agent connection props.set_property < std::string > ( AGENT_CONN_KW, svr_sid ); } } // if sid is not empty else { rodsLog( LOG_DEBUG, "%s - sent SID is empty", __FUNCTION__ ); } } // =-=-=-=-=-=-=- // check to see if the result string has the SSL negotiation results _result = kvp[ CS_NEG_RESULT_KW ]; if ( _result.empty() ) { return ERROR( UNMATCHED_KEY_OR_INDEX, "SSL result string missing from response" ); } } else { // =-=-=-=-=-=-=- // support 4.0 client-server negotiation which did not // use key-val pairs _result = read_cs_neg->result_; } } // if result strlen > 0 // =-=-=-=-=-=-=- // if the response is favorable, return success if ( CS_NEG_STATUS_SUCCESS == read_cs_neg->status_ ) { return SUCCESS(); } // =-=-=-=-=-=-=- // else, return a failure return ERROR( -1, "failure detected from client" ); } // client_server_negotiation_for_server
int msiobjget_z3950( msParam_t* inRequestPath, msParam_t* inFileMode, msParam_t* inFileFlags, msParam_t* inCacheFilename, ruleExecInfo_t* rei ) { char *reqStr; int mode; char *cacheFilename; char *str; int status, bytesWritten, objLen; int destFd; char *locStr, *queryStr, *syntaxStr; char *myMSICall; int i; ruleExecInfo_t rei2; msParamArray_t msParamArray; msParam_t *mP; RE_TEST_MACRO( " Calling msiobjget_z3950" ); /* check for input parameters */ if ( inRequestPath == NULL || strcmp( inRequestPath->type , STR_MS_T ) != 0 || inRequestPath->inOutStruct == NULL ) { return( USER_PARAM_TYPE_ERR ); } if ( inFileMode == NULL || strcmp( inFileMode->type , STR_MS_T ) != 0 || inFileMode->inOutStruct == NULL ) { return( USER_PARAM_TYPE_ERR ); } if ( inFileFlags == NULL || strcmp( inFileFlags->type , STR_MS_T ) != 0 || inFileFlags->inOutStruct == NULL ) { return( USER_PARAM_TYPE_ERR ); } if ( inCacheFilename == NULL || strcmp( inCacheFilename->type , STR_MS_T ) != 0 || inCacheFilename->inOutStruct == NULL ) { return( USER_PARAM_TYPE_ERR ); } /* coerce input to local variables */ reqStr = ( char * ) inRequestPath->inOutStruct; cacheFilename = ( char * ) inCacheFilename->inOutStruct; mode = atoi( ( char * ) inFileMode->inOutStruct ); /* Do the processing */ /* first skipping the mso-name */ if ( ( str = strstr( reqStr, ":" ) ) == NULL ) { str = reqStr; } else { str++; } /* getting parameters for the calls */ i = getz3950Params( str, &locStr, &queryStr, &syntaxStr ); if ( i != 0 ) { printf( "msiobjget_z3950: Error in request format for %s:%i\n", str, i ); return( USER_INPUT_FORMAT_ERR ); } myMSICall = ( char * ) malloc( strlen( reqStr ) + 200 ); sprintf( myMSICall, "msiz3950Submit(\"%s\",\"%s\",\"%s\",*OutBuffer)", locStr, queryStr, syntaxStr ); /* sprintf(myMSICall, "msiz3950Submit(\"z3950.loc.gov:7090/Voyager\",\"@attr 1=1003 Marx\",\"USMARC\",*OutBuffer)" ); printf("MM:%s***\n",myMSICall); */ free( locStr ); free( queryStr ); free( syntaxStr ); memset( ( char* )&rei2, 0, sizeof( ruleExecInfo_t ) ); memset( ( char* )&msParamArray, 0, sizeof( msParamArray_t ) ); rei2.rsComm = rei->rsComm; if ( rei2.rsComm != NULL ) { rei2.uoic = &rei2.rsComm->clientUser; rei2.uoip = &rei2.rsComm->proxyUser; } #ifdef RULE_ENGINE_N i = applyRuleUpdateParams( myMSICall, &msParamArray, &rei2, NO_SAVE_REI ); #else i = applyRule( myMSICall, &msParamArray, &rei2, NO_SAVE_REI ); #endif if ( i != 0 ) { printf( "msiobjget_z3950: Error in calling %s: %i\n", myMSICall, i ); free( myMSICall ); return( i ); } free( myMSICall ); mP = getMsParamByLabel( &msParamArray, "*OutBuffer" ); if ( mP == NULL ) { printf( "msiobjget_z3950: Error in Getting Parameter after call for *OutBuffer\n" ); return( UNKNOWN_PARAM_IN_RULE_ERR ); } str = ( char * ) mP->inOutStruct; objLen = strlen( str ); /* write the resulting buffer in cache file */ destFd = open( cacheFilename, O_WRONLY | O_CREAT | O_TRUNC, mode ); if ( destFd < 0 ) { status = UNIX_FILE_OPEN_ERR - errno; printf( "msigetobj_z3950: open error for cacheFilename %s, status = %d", cacheFilename, status ); clearMsParamArray( &msParamArray, 0 ); return status; } bytesWritten = write( destFd, str, objLen ); close( destFd ); clearMsParamArray( &msParamArray, 0 ); if ( bytesWritten != objLen ) { printf( "msigetobj_z3950: In Cache File %s bytesWritten %d != returned objLen %i\n", cacheFilename, bytesWritten, objLen ); return SYS_COPY_LEN_ERR; } /* clean up */ /*return */ return( 0 ); }
int rcDataObjRsync (rcComm_t *conn, dataObjInp_t *dataObjInp) { int status; msParamArray_t *outParamArray = NULL; char *locFilePath; status = _rcDataObjRsync (conn, dataObjInp, &outParamArray); if (status == SYS_SVR_TO_CLI_PUT_ACTION) { if ((locFilePath = getValByKey (&dataObjInp->condInput, RSYNC_DEST_PATH_KW)) == NULL) { return USER_INPUT_PATH_ERR; } else { status = rcDataObjPut (conn, dataObjInp, locFilePath); if (status >= 0) { return SYS_RSYNC_TARGET_MODIFIED; } else { return status; } } } else if (status == SYS_SVR_TO_CLI_GET_ACTION) { if ((locFilePath = getValByKey (&dataObjInp->condInput, RSYNC_DEST_PATH_KW)) == NULL) { return USER_INPUT_PATH_ERR; } else { status = rcDataObjGet (conn, dataObjInp, locFilePath); if (status >= 0) { return SYS_RSYNC_TARGET_MODIFIED; } else { return status; } } } /* below is for backward compatibility */ while (status == SYS_SVR_TO_CLI_MSI_REQUEST) { /* it is a server request */ msParam_t *myMsParam; dataObjInp_t *dataObjInp = NULL; int l1descInx; myMsParam = getMsParamByLabel (outParamArray, CL_ZONE_OPR_INX); if (myMsParam == NULL) { l1descInx = -1; } else { l1descInx = *(int*) myMsParam->inOutStruct; } if ((myMsParam = getMsParamByLabel (outParamArray, CL_PUT_ACTION)) != NULL) { dataObjInp = (dataObjInp_t *) myMsParam->inOutStruct; if ((locFilePath = getValByKey (&dataObjInp->condInput, RSYNC_DEST_PATH_KW)) == NULL) { if (l1descInx >= 0) { rcOprComplete (conn, l1descInx); } else { rcOprComplete (conn, USER_FILE_DOES_NOT_EXIST); } } else { status = rcDataObjPut (conn, dataObjInp, locFilePath); if (l1descInx >= 0) { rcOprComplete (conn, l1descInx); } else { rcOprComplete (conn, status); } } } else if ((myMsParam = getMsParamByLabel (outParamArray, CL_GET_ACTION)) != NULL) { dataObjInp = (dataObjInp_t *) myMsParam->inOutStruct; if ((locFilePath = getValByKey (&dataObjInp->condInput, RSYNC_DEST_PATH_KW)) == NULL) { if (l1descInx >= 0) { rcOprComplete (conn, l1descInx); } else { rcOprComplete (conn, USER_FILE_DOES_NOT_EXIST); } } else { status = rcDataObjGet (conn, dataObjInp, locFilePath); if (l1descInx >= 0) { rcOprComplete (conn, l1descInx); } else { rcOprComplete (conn, status); } } } else { if (l1descInx >= 0) { rcOprComplete (conn, l1descInx); } else { rcOprComplete (conn, SYS_SVR_TO_CLI_MSI_NO_EXIST); } } /* free outParamArray */ if (dataObjInp != NULL) { clearKeyVal (&dataObjInp->condInput); } clearMsParamArray (outParamArray, 1); free (outParamArray); /* read the reply from the eariler call */ status = branchReadAndProcApiReply (conn, DATA_OBJ_RSYNC_AN, (void **)&outParamArray, NULL); if (status < 0) { rodsLogError (LOG_DEBUG, status, "rcDataObjRsync: readAndProcApiReply failed. status = %d", status); } } return (status); }
void deleteMsParamArray(msParamArray_t *msParamArray) { clearMsParamArray(msParamArray,0); /* do not delete inOutStruct because global varaibles of iRODS type may share it */ /* to do write a function that delete inOutStruct of msParamArray if it is not shared */ free(msParamArray); }