static int dccp_v6_rcv(struct sk_buff *skb)
{
	const struct dccp_hdr *dh;
	struct sock *sk;
	int min_cov;

	/* Step 1: Check header basics */

	if (dccp_invalid_packet(skb))
		goto discard_it;

	/* Step 1: If header checksum is incorrect, drop packet and return. */
	if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
				     &ipv6_hdr(skb)->daddr)) {
		DCCP_WARN("dropped packet with invalid checksum\n");
		goto discard_it;
	}

	dh = dccp_hdr(skb);

	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh);
	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;

	if (dccp_packet_without_ack(skb))
		DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;
	else
		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);

lookup:
	sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
			        dh->dccph_sport, dh->dccph_dport,
				inet6_iif(skb));
	if (!sk) {
		dccp_pr_debug("failed to look up flow ID in table and "
			      "get corresponding socket\n");
		goto no_dccp_socket;
	}

	/*
	 * Step 2:
	 *	... or S.state == TIMEWAIT,
	 *		Generate Reset(No Connection) unless P.type == Reset
	 *		Drop packet and return
	 */
	if (sk->sk_state == DCCP_TIME_WAIT) {
		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");
		inet_twsk_put(inet_twsk(sk));
		goto no_dccp_socket;
	}

	if (sk->sk_state == DCCP_NEW_SYN_RECV) {
		struct request_sock *req = inet_reqsk(sk);
		struct sock *nsk = NULL;

		sk = req->rsk_listener;
		if (likely(sk->sk_state == DCCP_LISTEN)) {
			nsk = dccp_check_req(sk, skb, req);
		} else {
			inet_csk_reqsk_queue_drop_and_put(sk, req);
			goto lookup;
		}
		if (!nsk) {
			reqsk_put(req);
			goto discard_it;
		}
		if (nsk == sk) {
			sock_hold(sk);
			reqsk_put(req);
		} else if (dccp_child_process(sk, nsk, skb)) {
			dccp_v6_ctl_send_reset(sk, skb);
			goto discard_it;
		} else {
			return 0;
		}
	}
	/*
	 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
	 *	o if MinCsCov = 0, only packets with CsCov = 0 are accepted
	 *	o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
	 */
	min_cov = dccp_sk(sk)->dccps_pcrlen;
	if (dh->dccph_cscov  &&  (min_cov == 0 || dh->dccph_cscov < min_cov))  {
		dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
			      dh->dccph_cscov, min_cov);
		/* FIXME: send Data Dropped option (see also dccp_v4_rcv) */
		goto discard_and_relse;
	}

	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
		goto discard_and_relse;

	return sk_receive_skb(sk, skb, 1) ? -1 : 0;

no_dccp_socket:
	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
		goto discard_it;
	/*
	 * Step 2:
	 *	If no socket ...
	 *		Generate Reset(No Connection) unless P.type == Reset
	 *		Drop packet and return
	 */
	if (dh->dccph_type != DCCP_PKT_RESET) {
		DCCP_SKB_CB(skb)->dccpd_reset_code =
					DCCP_RESET_CODE_NO_CONNECTION;
		dccp_v6_ctl_send_reset(sk, skb);
	}

discard_it:
	kfree_skb(skb);
	return 0;

discard_and_relse:
	sock_put(sk);
	goto discard_it;
}


static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
	if (skb->protocol == htons(ETH_P_IP))
		return tcp_v4_conn_request(sk, skb);

	if (!ipv6_unicast_destination(skb))
		goto drop;

	return tcp_conn_request(&tcp6_request_sock_ops,
				&tcp_request_sock_ipv6_ops, sk, skb);

drop:
	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
	return 0; /* don't send reset */
}


static inline void ipv6_addr_set_v4mapped(const __be32 addr,
					  struct in6_addr *v4mapped)
{
	ipv6_addr_set(v4mapped,
			0, 0,
			htonl(0x0000FFFF),
			addr);
}


void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
{
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;

	sin6->sin6_family = AF_INET6;
	sin6->sin6_addr = sk->sk_v6_daddr;
	sin6->sin6_port	= inet_sk(sk)->inet_dport;
	/* We do not store received flowlabel for TCP */
	sin6->sin6_flowinfo = 0;
	sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
						  sk->sk_bound_dev_if);
}


static inline int snmp6_register_dev(struct inet6_dev *idev) { return 0; }


static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
				  int optname, char __user *optval, int len)
{
	struct ipv6_opt_hdr *hdr;

	if (!opt)
		return 0;

	switch (optname) {
	case IPV6_HOPOPTS:
		hdr = opt->hopopt;
		break;
	case IPV6_RTHDRDSTOPTS:
		hdr = opt->dst0opt;
		break;
	case IPV6_RTHDR:
		hdr = (struct ipv6_opt_hdr *)opt->srcrt;
		break;
	case IPV6_DSTOPTS:
		hdr = opt->dst1opt;
		break;
	default:
		return -EINVAL;	/* should not happen */
	}

	if (!hdr)
		return 0;

	len = min_t(unsigned int, len, ipv6_optlen(hdr));
	if (copy_to_user(optval, hdr, len))
		return -EFAULT;
	return len;
}


lock_pool (void)
{
  int err;

  err = gpgrt_lock_lock (&pool_lock);
  if (err)
    log_fatal ("failed to acquire the pool lock: %s\n", gpg_strerror (err));
  pool_is_locked = 1;
}


_gcry_rngcsprng_use_daemon (int onoff)
{
#ifdef USE_RANDOM_DAEMON
  int last;

  /* This is not really thread safe.  However it is expected that this
     function is being called during initialization and at that point
     we are for other reasons not really thread safe.  We do not want
     to lock it because we might eventually decide that this function
     may even be called prior to gcry_check_version.  */
  last = allow_daemon;
  if (onoff != -1)
    allow_daemon = onoff;

  return last;
#else /*!USE_RANDOM_DAEMON*/
  (void)onoff;
  return 0;
#endif /*!USE_RANDOM_DAEMON*/
}


initialize_basics(void)
{
  static int initialized;

  if (!initialized)
    {
      initialized = 1;

#ifdef USE_RANDOM_DAEMON
      _gcry_daemon_initialize_basics ();
#endif /*USE_RANDOM_DAEMON*/

      /* Make sure that we are still using the values we have
         traditionally used for the random levels.  */
      gcry_assert (GCRY_WEAK_RANDOM == 0
                   && GCRY_STRONG_RANDOM == 1
                   && GCRY_VERY_STRONG_RANDOM == 2);
    }
}


_gcry_rngcsprng_fast_poll (void)
{
  initialize_basics ();

  lock_pool ();
  if (rndpool)
    {
      /* Yes, we are fully initialized. */
      do_fast_random_poll ();
    }
  unlock_pool ();
}


add_randomness( const void *buffer, size_t length, int source )
{
    const byte *p = buffer;

    if( !is_initialized )
	initialize();
    rndstats.addbytes += length;
    rndstats.naddbytes++;
    while( length-- ) {
	rndpool[pool_writepos++] ^= *p++;
	if( pool_writepos >= POOLSIZE ) {
	    if( source > 1 )
		pool_filled = 1;
	    pool_writepos = 0;
	    mix_pool(rndpool); rndstats.mixrnd++;
	    just_mixed = !length;
	}
    }
}


randomize_mpi (MPI mpi, size_t nbits, int level)
{
  unsigned char *buffer;

  buffer = get_random_bits (nbits, level, mpi_is_secure (mpi));
  mpi_set_buffer (mpi, buffer, (nbits+7)/8, 0);
  xfree (buffer);
}


random_poll()
{
    rndstats.slowpolls++;
    read_random_source( 2, POOLSIZE/5, 1 );
}


randomize_buffer( byte *buffer, size_t length, int level )
{
    char *p = get_random_bits( length*8, level, 1 );
    memcpy( buffer, p, length );
    xfree(p);
}


mnote_pentax_entry_get_value (MnotePentaxEntry *entry,
			      char *val, unsigned int maxlen)
{
	ExifLong vl;
	ExifShort vs, vs2;
	int i = 0, j = 0;

	if (!entry) return (NULL);

	memset (val, 0, maxlen);
	maxlen--;

	switch (entry->tag) {
	  case MNOTE_PENTAX_TAG_MODE:
	  case MNOTE_PENTAX_TAG_QUALITY:
	  case MNOTE_PENTAX_TAG_FOCUS:
	  case MNOTE_PENTAX_TAG_FLASH:
	  case MNOTE_PENTAX_TAG_WHITE_BALANCE:
	  case MNOTE_PENTAX_TAG_SHARPNESS:
	  case MNOTE_PENTAX_TAG_CONTRAST:
	  case MNOTE_PENTAX_TAG_SATURATION:
	  case MNOTE_PENTAX_TAG_ISO_SPEED:
	  case MNOTE_PENTAX_TAG_COLOR:
	  case MNOTE_PENTAX2_TAG_MODE:
	  case MNOTE_PENTAX2_TAG_QUALITY:
	  case MNOTE_PENTAX2_TAG_FLASH_MODE:
	  case MNOTE_PENTAX2_TAG_FOCUS_MODE:
	  case MNOTE_PENTAX2_TAG_AFPOINT_SELECTED:
	  case MNOTE_PENTAX2_TAG_AUTO_AFPOINT:
	  case MNOTE_PENTAX2_TAG_WHITE_BALANCE:
	  case MNOTE_PENTAX2_TAG_PICTURE_MODE:
	  case MNOTE_PENTAX2_TAG_IMAGE_SIZE:
	  case MNOTE_CASIO2_TAG_BESTSHOT_MODE:
		CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen);
		CC2 (entry->components, 1, 2, val, maxlen);
		if (entry->components == 1) {
			vs = exif_get_short (entry->data, entry->order);

			/* search the tag */
			for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++);
			if (!items[i].tag) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i)"), vs);
			  	break;
			}

			/* find the value */
			for (j = 0; items[i].elem[j].string &&
			    (items[i].elem[j].index < vs); j++);
			if (items[i].elem[j].index != vs) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i)"), vs);
				break;
			}
			strncpy (val, _(items[i].elem[j].string), maxlen);
		} else {
			/* Two-component values */
			CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen);
			CC2 (entry->components, 1, 2, val, maxlen);
			vs = exif_get_short (entry->data, entry->order);
			vs2 = exif_get_short (entry->data+2, entry->order) << 16;

			/* search the tag */
			for (i = 0; (items2[i].tag && items2[i].tag != entry->tag); i++);
			if (!items2[i].tag) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i %i)"), vs, vs2);
			  	break;
			}

			/* find the value */
			for (j = 0; items2[i].elem[j].string && ((items2[i].elem[j].index2 < vs2)
				|| ((items2[i].elem[j].index2 == vs2) && (items2[i].elem[j].index1 < vs))); j++);
			if ((items2[i].elem[j].index1 != vs) || (items2[i].elem[j].index2 != vs2)) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i %i)"), vs, vs2);
				break;
			}
			strncpy (val, _(items2[i].elem[j].string), maxlen);
		}
		break;

	case MNOTE_PENTAX_TAG_ZOOM:
		CF (entry->format, EXIF_FORMAT_LONG, val, maxlen);
		CC (entry->components, 1, val, maxlen);
		vl = exif_get_long (entry->data, entry->order);
		snprintf (val, maxlen, "%li", (long int) vl);
		break;
	case MNOTE_PENTAX_TAG_PRINTIM:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (entry->components, 124, val, maxlen);
		snprintf (val, maxlen, _("%i bytes unknown data"),
			entry->size);
		break;
	case MNOTE_PENTAX_TAG_TZ_CITY:
	case MNOTE_PENTAX_TAG_TZ_DST:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (entry->components, 4, val, maxlen);
		strncpy (val, (char*)entry->data, MIN(maxlen, entry->size));
		break;
	case MNOTE_PENTAX2_TAG_DATE:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (entry->components, 4, val, maxlen);
		/* Note: format is UNDEFINED, not SHORT -> order is fixed: MOTOROLA */
		vs = exif_get_short (entry->data, EXIF_BYTE_ORDER_MOTOROLA);
		snprintf (val, maxlen, "%i:%02i:%02i", vs, entry->data[2], entry->data[3]);
		break;
	case MNOTE_PENTAX2_TAG_TIME:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC2 (entry->components, 3, 4, val, maxlen);
		snprintf (val, maxlen, "%02i:%02i:%02i", entry->data[0], entry->data[1], entry->data[2]);
		break;
	default:
		switch (entry->format) {
		case EXIF_FORMAT_ASCII:
		  strncpy (val, (char *)entry->data, MIN(maxlen, entry->size));
		  break;
		case EXIF_FORMAT_SHORT:
		  {
			const unsigned char *data = entry->data;
		  	size_t k, len = strlen(val), sizeleft;

			sizeleft = entry->size;
		  	for(k=0; k<entry->components; k++) {
				if (sizeleft < 2)
					break;
				vs = exif_get_short (data, entry->order);
				snprintf (val+len, maxlen-len, "%i ", vs);
				len = strlen(val);
				data += 2;
				sizeleft -= 2;
			}
		  }
		  break;
		case EXIF_FORMAT_LONG:
		  {
			const unsigned char *data = entry->data;
		  	size_t k, len = strlen(val), sizeleft;

			sizeleft = entry->size;
		  	for(k=0; k<entry->components; k++) {
				if (sizeleft < 4)
					break;
				vl = exif_get_long (data, entry->order);
				snprintf (val+len, maxlen-len, "%li", (long int) vl);
				len = strlen(val);
				data += 4;
				sizeleft -= 4;
			}
		  }
		  break;
		case EXIF_FORMAT_UNDEFINED:
		default:
		  snprintf (val, maxlen, _("%i bytes unknown data"),
			  entry->size);
		  break;
		}
		break;
	}

	return val;
}


static inline bool tcp_in_slow_start(const struct tcp_sock *tp)
{
	return tp->snd_cwnd < tp->snd_ssthresh;
}


static inline void tcp_segs_in(struct tcp_sock *tp, const struct sk_buff *skb)
{
	u16 segs_in;

	segs_in = max_t(u16, 1, skb_shinfo(skb)->gso_segs);
	tp->segs_in += segs_in;
	if (skb->len > tcp_hdrlen(skb))
		tp->data_segs_in += segs_in;
}


static inline struct sk_buff *tcp_write_queue_next(const struct sock *sk,
						   const struct sk_buff *skb)
{
	return skb_queue_next(&sk->sk_write_queue, skb);
}


static inline void tcp_synq_overflow(const struct sock *sk)
{
	unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
	unsigned long now = jiffies;

	if (time_after(now, last_overflow + HZ))
		tcp_sk(sk)->rx_opt.ts_recent_stamp = now;
}


static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
{
	struct net *net = sock_net((struct sock *)tp);
	return tp->notsent_lowat ?: net->ipv4.sysctl_tcp_notsent_lowat;
}


static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq)
{
	tp->snd_wl1 = seq;
}


static inline bool tcp_stream_is_thin(struct tcp_sock *tp)
{
	return tp->packets_out < 4 && !tcp_in_initial_slowstart(tp);
}


void DupTagTypeList(struct _cmsContext_struct* ctx,
                    const struct _cmsContext_struct* src,
                    int loc)
{
   _cmsTagTypePluginChunkType newHead = { NULL };
   _cmsTagTypeLinkedList*  entry;
   _cmsTagTypeLinkedList*  Anterior = NULL;
   _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc];

   // Walk the list copying all nodes
   for (entry = head->TagTypes;
       entry != NULL;
       entry = entry ->Next) {

           _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList));

           if (newEntry == NULL)
               return;

           // We want to keep the linked list order, so this is a little bit tricky
           newEntry -> Next = NULL;
           if (Anterior)
               Anterior -> Next = newEntry;

           Anterior = newEntry;

           if (newHead.TagTypes == NULL)
               newHead.TagTypes = newEntry;
   }

   ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType));
}


void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
{
    cmsICCMeasurementConditions mc;

    memset(&mc, 0, sizeof(mc));

    if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
    if (!_cmsReadXYZNumber(io,    &mc.Backing)) return NULL;
    if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
    if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
    if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;

    *nItems = 1;
    return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));

    cmsUNUSED_PARAMETER(SizeOfTag);
}


cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
{
    cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
    _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos);
    _cmsTagTypeLinkedList *pt;

    // Calling the function with NULL as plug-in would unregister the plug in.
    if (Data == NULL) {

        // There is no need to set free the memory, as pool is destroyed as a whole.
        ctx ->TagTypes = NULL;
        return TRUE;
    }

    // Registering happens in plug-in memory pool.
    pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
    if (pt == NULL) return FALSE;

    pt ->Handler   = Plugin ->Handler;
    pt ->Next      = ctx ->TagTypes;

    ctx ->TagTypes = pt;

    return TRUE;
}


cmsBool _MultiplyMatrix(cmsPipeline* Lut)
{
       cmsStage** pt1;
       cmsStage** pt2;
       cmsStage*  chain;
       cmsBool AnyOpt = FALSE;

       pt1 = &Lut->Elements;
       if (*pt1 == NULL) return AnyOpt;

       while (*pt1 != NULL) {

              pt2 = &((*pt1)->Next);
              if (*pt2 == NULL) return AnyOpt;

              if ((*pt1)->Implements == cmsSigMatrixElemType && (*pt2)->Implements == cmsSigMatrixElemType) {

                     // Get both matrices
                     _cmsStageMatrixData* m1 = (_cmsStageMatrixData*) cmsStageData(*pt1);
                     _cmsStageMatrixData* m2 = (_cmsStageMatrixData*) cmsStageData(*pt2);
                     cmsMAT3 res;

                     // Input offset and output offset should be zero to use this optimization
                     if (m1->Offset != NULL || m2 ->Offset != NULL ||
                            cmsStageInputChannels(*pt1) != 3 || cmsStageOutputChannels(*pt1) != 3 ||
                            cmsStageInputChannels(*pt2) != 3 || cmsStageOutputChannels(*pt2) != 3)
                            return FALSE;

                     // Multiply both matrices to get the result
                     _cmsMAT3per(&res, (cmsMAT3*)m2->Double, (cmsMAT3*)m1->Double);

                     // Get the next in chain after the matrices
                     chain = (*pt2)->Next;

                     // Remove both matrices
                     _RemoveElement(pt2);
                     _RemoveElement(pt1);

                     // Now what if the result is a plain identity?
                     if (!isFloatMatrixIdentity(&res)) {

                            // We can not get rid of full matrix
                            cmsStage* Multmat = cmsStageAllocMatrix(Lut->ContextID, 3, 3, (const cmsFloat64Number*) &res, NULL);
                            if (Multmat == NULL) return FALSE;  // Should never happen

                            // Recover the chain
                            Multmat->Next = chain;
                            *pt1 = Multmat;
                     }

                     AnyOpt = TRUE;
              }
              else
                     pt1 = &((*pt1)->Next);
       }

       return AnyOpt;
}


cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] )
{
    int i;

    for (i=0; i < n; i++) {

        if (abs(White1[i] - White2[i]) > 0xf000) return TRUE;  // Values are so extremely different that the fixup should be avoided
        if (White1[i] != White2[i]) return FALSE;
    }
    return TRUE;
}


void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
{
    cmsUInt32Number      BaseOffset;
    cmsUInt8Number       inputChan;      // Number of input channels
    cmsUInt8Number       outputChan;     // Number of output channels
    cmsUInt32Number      offsetB;        // Offset to first "B" curve
    cmsUInt32Number      offsetMat;      // Offset to matrix
    cmsUInt32Number      offsetM;        // Offset to first "M" curve
    cmsUInt32Number      offsetC;        // Offset to CLUT
    cmsUInt32Number      offsetA;        // Offset to first "A" curve
    cmsPipeline* NewLUT = NULL;

    BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);

    if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
    if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;

    if (!_cmsReadUInt16Number(io, NULL)) return NULL;

    if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
    if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
    if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
    if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
    if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;

    if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
    if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;

    // Allocates an empty LUT
    NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
    if (NewLUT == NULL) return NULL;

    if (offsetA!= 0) {
        if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan)))
            goto Error;
    }

    if (offsetC != 0) {
        if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
            goto Error;
    }

    if (offsetM != 0) {
        if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
            goto Error;
    }

    if (offsetMat != 0) {
        if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
            goto Error;
    }

    if (offsetB != 0) {
        if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
            goto Error;
    }

    *nItems = 1;
    return NewLUT;
Error:
    cmsPipelineFree(NewLUT);
    return NULL;

    cmsUNUSED_PARAMETER(SizeOfTag);
}


void* CurvesDup(cmsContext ContextID, const void* ptr)
{
    Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
    int i;

    if (Data == NULL) return NULL;

    Data->Curves = (cmsUInt16Number**) _cmsDupMem(ContextID, Data->Curves, Data->nCurves * sizeof(cmsUInt16Number*));

    for (i=0; i < Data -> nCurves; i++) {
        Data->Curves[i] = (cmsUInt16Number*) _cmsDupMem(ContextID, Data->Curves[i], Data->nElements * sizeof(cmsUInt16Number));
    }

    return (void*) Data;
}


void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput)
{
    int i;
    cmsFloat32Number R, Val;

    for (i=0; i < 16385; i++) {

        R   = (cmsFloat32Number) (i / 16384.0);
        Val = cmsEvalToneCurveFloat(Curve, R);    // Val comes 0..1.0

        if (Val < 0)
            Val = 0;

        if (Val > 1.0)
            Val = 1.0;

        if (Is8BitsOutput) {

            // If 8 bits output, we can optimize further by computing the / 257 part.
            // first we compute the resulting byte and then we store the byte times
            // 257. This quantization allows to round very quick by doing a >> 8, but
            // since the low byte is always equal to msb, we can do a & 0xff and this works!
            cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0);
            cmsUInt8Number  b = FROM_16_TO_8(w);

            Table[i] = FROM_8_TO_16(b);
        }
        else Table[i]  = _cmsQuickSaturateWord(Val * 65535.0);
    }
}


static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size)
{
	struct f2fs_acl_header *f2fs_acl;
	struct f2fs_acl_entry *entry;
	int i;

	f2fs_acl = f2fs_kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count *
			sizeof(struct f2fs_acl_entry), GFP_NOFS);
	if (!f2fs_acl)
		return ERR_PTR(-ENOMEM);

	f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION);
	entry = (struct f2fs_acl_entry *)(f2fs_acl + 1);

	for (i = 0; i < acl->a_count; i++) {

		entry->e_tag  = cpu_to_le16(acl->a_entries[i].e_tag);
		entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm);

		switch (acl->a_entries[i].e_tag) {
		case ACL_USER:
			entry->e_id = cpu_to_le32(
					from_kuid(&init_user_ns,
						acl->a_entries[i].e_uid));
			entry = (struct f2fs_acl_entry *)((char *)entry +
					sizeof(struct f2fs_acl_entry));
			break;
		case ACL_GROUP:
			entry->e_id = cpu_to_le32(
					from_kgid(&init_user_ns,
						acl->a_entries[i].e_gid));
			entry = (struct f2fs_acl_entry *)((char *)entry +
					sizeof(struct f2fs_acl_entry));
			break;
		case ACL_USER_OBJ:
		case ACL_GROUP_OBJ:
		case ACL_MASK:
		case ACL_OTHER:
			entry = (struct f2fs_acl_entry *)((char *)entry +
					sizeof(struct f2fs_acl_entry_short));
			break;
		default:
			goto fail;
		}
	}
	*size = f2fs_acl_size(acl->a_count);
	return (void *)f2fs_acl;

fail:
	kfree(f2fs_acl);
	return ERR_PTR(-EINVAL);
}


int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
{
	int err = 0;
	struct posix_acl *default_acl, *acl;

	hfs_dbg(ACL_MOD,
		"[%s]: ino %lu, dir->ino %lu\n",
		__func__, inode->i_ino, dir->i_ino);

	if (S_ISLNK(inode->i_mode))
		return 0;

	err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (err)
		return err;

	if (default_acl) {
		err = hfsplus_set_posix_acl(inode, default_acl,
					    ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!err)
			err = hfsplus_set_posix_acl(inode, acl,
						    ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}
	return err;
}


struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
{
	int size;
	const char *name;
	char *value = NULL;
	struct posix_acl *acl;

	switch (type) {
	case ACL_TYPE_ACCESS:
		name = XATTR_NAME_POSIX_ACL_ACCESS;
		break;
	case ACL_TYPE_DEFAULT:
		name = XATTR_NAME_POSIX_ACL_DEFAULT;
		break;
	default:
		BUG();
	}

	size = __btrfs_getxattr(inode, name, "", 0);
	if (size > 0) {
		value = kzalloc(size, GFP_KERNEL);
		if (!value)
			return ERR_PTR(-ENOMEM);
		size = __btrfs_getxattr(inode, name, value, size);
	}
	if (size > 0) {
		acl = posix_acl_from_xattr(&init_user_ns, value, size);
	} else if (size == -ERANGE || size == -ENODATA || size == 0) {
		acl = NULL;
	} else {
		acl = ERR_PTR(-EIO);
	}
	kfree(value);

	return acl;
}


static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
{
	struct ocfs2_acl_entry *entry = NULL;
	char *ocfs2_acl;
	size_t n;

	*size = acl->a_count * sizeof(struct posix_acl_entry);

	ocfs2_acl = kmalloc(*size, GFP_NOFS);
	if (!ocfs2_acl)
		return ERR_PTR(-ENOMEM);

	entry = (struct ocfs2_acl_entry *)ocfs2_acl;
	for (n = 0; n < acl->a_count; n++, entry++) {
		entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
		switch(acl->a_entries[n].e_tag) {
		case ACL_USER:
			entry->e_id = cpu_to_le32(
				from_kuid(&init_user_ns,
					  acl->a_entries[n].e_uid));
			break;
		case ACL_GROUP:
			entry->e_id = cpu_to_le32(
				from_kgid(&init_user_ns,
					  acl->a_entries[n].e_gid));
			break;
		default:
			entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
			break;
		}
	}
	return ocfs2_acl;
}


__ext4_set_acl(handle_t *handle, struct inode *inode, int type,
	     struct posix_acl *acl)
{
	int name_index;
	void *value = NULL;
	size_t size = 0;
	int error;

	switch (type) {
	case ACL_TYPE_ACCESS:
		name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
		if (acl) {
			error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
			if (error)
				return error;
			inode->i_ctime = ext4_current_time(inode);
			ext4_mark_inode_dirty(handle, inode);
		}
		break;

	case ACL_TYPE_DEFAULT:
		name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
		if (!S_ISDIR(inode->i_mode))
			return acl ? -EACCES : 0;
		break;

	default:
		return -EINVAL;
	}
	if (acl) {
		value = ext4_acl_to_disk(acl, &size);
		if (IS_ERR(value))
			return (int)PTR_ERR(value);
	}

	error = ext4_xattr_set_handle(handle, inode, name_index, "",
				      value, size, 0);

	kfree(value);
	if (!error)
		set_cached_acl(inode, type, acl);

	return error;
}


int v9fs_acl_mode(struct inode *dir, umode_t *modep,
		  struct posix_acl **dpacl, struct posix_acl **pacl)
{
	int retval = 0;
	umode_t mode = *modep;
	struct posix_acl *acl = NULL;

	if (!S_ISLNK(mode)) {
		acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
		if (IS_ERR(acl))
			return PTR_ERR(acl);
		if (!acl)
			mode &= ~current_umask();
	}
	if (acl) {
		if (S_ISDIR(mode))
			*dpacl = posix_acl_dup(acl);
		retval = __posix_acl_create(&acl, GFP_NOFS, &mode);
		if (retval < 0)
			return retval;
		if (retval > 0)
			*pacl = acl;
		else
			posix_acl_release(acl);
	}
	*modep  = mode;
	return 0;
}


void v9fs_put_acl(struct posix_acl *dacl,
		  struct posix_acl *acl)
{
	posix_acl_release(dacl);
	posix_acl_release(acl);
}


static struct posix_acl *reiserfs_posix_acl_from_disk(const void *value, size_t size)
{
	const char *end = (char *)value + size;
	int n, count;
	struct posix_acl *acl;

	if (!value)
		return NULL;
	if (size < sizeof(reiserfs_acl_header))
		return ERR_PTR(-EINVAL);
	if (((reiserfs_acl_header *) value)->a_version !=
	    cpu_to_le32(REISERFS_ACL_VERSION))
		return ERR_PTR(-EINVAL);
	value = (char *)value + sizeof(reiserfs_acl_header);
	count = reiserfs_acl_count(size);
	if (count < 0)
		return ERR_PTR(-EINVAL);
	if (count == 0)
		return NULL;
	acl = posix_acl_alloc(count, GFP_NOFS);
	if (!acl)
		return ERR_PTR(-ENOMEM);
	for (n = 0; n < count; n++) {
		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
		if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
			goto fail;
		acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
		switch (acl->a_entries[n].e_tag) {
		case ACL_USER_OBJ:
		case ACL_GROUP_OBJ:
		case ACL_MASK:
		case ACL_OTHER:
			value = (char *)value +
			    sizeof(reiserfs_acl_entry_short);
			break;

		case ACL_USER:
			value = (char *)value + sizeof(reiserfs_acl_entry);
			if ((char *)value > end)
				goto fail;
			acl->a_entries[n].e_uid =
				make_kuid(&init_user_ns,
					  le32_to_cpu(entry->e_id));
			break;
		case ACL_GROUP:
			value = (char *)value + sizeof(reiserfs_acl_entry);
			if ((char *)value > end)
				goto fail;
			acl->a_entries[n].e_gid =
				make_kgid(&init_user_ns,
					  le32_to_cpu(entry->e_id));
			break;

		default:
			goto fail;
		}
	}
	if (value != end)
		goto fail;
	return acl;

fail:
	posix_acl_release(acl);
	return ERR_PTR(-EINVAL);
}


ext2_acl_from_disk(const void *value, size_t size)
{
	const char *end = (char *)value + size;
	int n, count;
	struct posix_acl *acl;

	if (!value)
		return NULL;
	if (size < sizeof(ext2_acl_header))
		 return ERR_PTR(-EINVAL);
	if (((ext2_acl_header *)value)->a_version !=
	    cpu_to_le32(EXT2_ACL_VERSION))
		return ERR_PTR(-EINVAL);
	value = (char *)value + sizeof(ext2_acl_header);
	count = ext2_acl_count(size);
	if (count < 0)
		return ERR_PTR(-EINVAL);
	if (count == 0)
		return NULL;
	acl = posix_acl_alloc(count, GFP_KERNEL);
	if (!acl)
		return ERR_PTR(-ENOMEM);
	for (n=0; n < count; n++) {
		ext2_acl_entry *entry =
			(ext2_acl_entry *)value;
		if ((char *)value + sizeof(ext2_acl_entry_short) > end)
			goto fail;
		acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
		switch(acl->a_entries[n].e_tag) {
			case ACL_USER_OBJ:
			case ACL_GROUP_OBJ:
			case ACL_MASK:
			case ACL_OTHER:
				value = (char *)value +
					sizeof(ext2_acl_entry_short);
				break;

			case ACL_USER:
				value = (char *)value + sizeof(ext2_acl_entry);
				if ((char *)value > end)
					goto fail;
				acl->a_entries[n].e_uid =
					make_kuid(&init_user_ns,
						  le32_to_cpu(entry->e_id));
				break;
			case ACL_GROUP:
				value = (char *)value + sizeof(ext2_acl_entry);
				if ((char *)value > end)
					goto fail;
				acl->a_entries[n].e_gid =
					make_kgid(&init_user_ns,
						  le32_to_cpu(entry->e_id));
				break;

			default:
				goto fail;
		}
	}
	if (value != end)
		goto fail;
	return acl;

fail:
	posix_acl_release(acl);
	return ERR_PTR(-EINVAL);
}


struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
{
	struct posix_acl *acl;
	char *xattr_name;
	char *value = NULL;
	ssize_t size;

	hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);

	switch (type) {
	case ACL_TYPE_ACCESS:
		xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
		break;
	case ACL_TYPE_DEFAULT:
		xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
		break;
	default:
		return ERR_PTR(-EINVAL);
	}

	size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);

	if (size > 0) {
		value = (char *)hfsplus_alloc_attr_entry();
		if (unlikely(!value))
			return ERR_PTR(-ENOMEM);
		size = __hfsplus_getxattr(inode, xattr_name, value, size);
	}

	if (size > 0)
		acl = posix_acl_from_xattr(&init_user_ns, value, size);
	else if (size == -ENODATA)
		acl = NULL;
	else
		acl = ERR_PTR(size);

	hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);

	return acl;
}


static inline void ceph_set_cached_acl(struct inode *inode,
					int type, struct posix_acl *acl)
{
	struct ceph_inode_info *ci = ceph_inode(inode);

	spin_lock(&ci->i_ceph_lock);
	if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0))
		set_cached_acl(inode, type, acl);
	else
		forget_cached_acl(inode, type);
	spin_unlock(&ci->i_ceph_lock);
}


static inline int f2fs_acl_count(size_t size)
{
	ssize_t s;
	size -= sizeof(struct f2fs_acl_header);
	s = size - 4 * sizeof(struct f2fs_acl_entry_short);
	if (s < 0) {
		if (size % sizeof(struct f2fs_acl_entry_short))
			return -1;
		return size / sizeof(struct f2fs_acl_entry_short);
	} else {
		if (s % sizeof(struct f2fs_acl_entry))
			return -1;
		return s / sizeof(struct f2fs_acl_entry) + 4;
	}
}


posix_acl_from_xattr(struct user_namespace *user_ns,
		     const void *value, size_t size)
{
	const struct posix_acl_xattr_header *header = value;
	const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end;
	int count;
	struct posix_acl *acl;
	struct posix_acl_entry *acl_e;

	if (!value)
		return NULL;
	if (size < sizeof(struct posix_acl_xattr_header))
		 return ERR_PTR(-EINVAL);
	if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
		return ERR_PTR(-EOPNOTSUPP);

	count = posix_acl_xattr_count(size);
	if (count < 0)
		return ERR_PTR(-EINVAL);
	if (count == 0)
		return NULL;

	acl = posix_acl_alloc(count, GFP_NOFS);
	if (!acl)
		return ERR_PTR(-ENOMEM);
	acl_e = acl->a_entries;

	for (end = entry + count; entry != end; acl_e++, entry++) {
		acl_e->e_tag  = le16_to_cpu(entry->e_tag);
		acl_e->e_perm = le16_to_cpu(entry->e_perm);

		switch(acl_e->e_tag) {
			case ACL_USER_OBJ:
			case ACL_GROUP_OBJ:
			case ACL_MASK:
			case ACL_OTHER:
				break;

			case ACL_USER:
				acl_e->e_uid =
					make_kuid(user_ns,
						  le32_to_cpu(entry->e_id));
				if (!uid_valid(acl_e->e_uid))
					goto fail;
				break;
			case ACL_GROUP:
				acl_e->e_gid =
					make_kgid(user_ns,
						  le32_to_cpu(entry->e_id));
				if (!gid_valid(acl_e->e_gid))
					goto fail;
				break;

			default:
				goto fail;
		}
	}
	return acl;

fail:
	posix_acl_release(acl);
	return ERR_PTR(-EINVAL);
}


static void vmxnet3_reset(VMXNET3State *s)
{
    VMW_CBPRN("Resetting vmxnet3...");

    vmxnet3_deactivate_device(s);
    vmxnet3_reset_interrupt_states(s);
    s->drv_shmem = 0;
    s->tx_sop = true;
    s->skip_current_tx_pkt = false;
}


vmxnet3_io_bar1_read(void *opaque, hwaddr addr, unsigned size)
{
        VMXNET3State *s = opaque;
        uint64_t ret = 0;

        switch (addr) {
        /* Vmxnet3 Revision Report Selection */
        case VMXNET3_REG_VRRS:
            VMW_CBPRN("Read BAR1 [VMXNET3_REG_VRRS], size %d", size);
            ret = VMXNET3_DEVICE_REVISION;
            break;

        /* UPT Version Report Selection */
        case VMXNET3_REG_UVRS:
            VMW_CBPRN("Read BAR1 [VMXNET3_REG_UVRS], size %d", size);
            ret = VMXNET3_UPT_REVISION;
            break;

        /* Command */
        case VMXNET3_REG_CMD:
            VMW_CBPRN("Read BAR1 [VMXNET3_REG_CMD], size %d", size);
            ret = vmxnet3_get_command_status(s);
            break;

        /* MAC Address Low */
        case VMXNET3_REG_MACL:
            VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACL], size %d", size);
            ret = vmxnet3_get_mac_low(&s->conf.macaddr);
            break;

        /* MAC Address High */
        case VMXNET3_REG_MACH:
            VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACH], size %d", size);
            ret = vmxnet3_get_mac_high(&s->conf.macaddr);
            break;

        /*
         * Interrupt Cause Register
         * Used for legacy interrupts only so interrupt index always 0
         */
        case VMXNET3_REG_ICR:
            VMW_CBPRN("Read BAR1 [VMXNET3_REG_ICR], size %d", size);
            if (vmxnet3_interrupt_asserted(s, 0)) {
                vmxnet3_clear_interrupt(s, 0);
                ret = true;
            } else {
                ret = false;
            }
            break;

        default:
            VMW_CBPRN("Unknow read BAR1[%" PRIx64 "], %d bytes", addr, size);
            break;
        }

        return ret;
}


static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx)
{
    struct Vmxnet3_TxCompDesc txcq_descr;
    PCIDevice *d = PCI_DEVICE(s);

    VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);

    txcq_descr.txdIdx = tx_ridx;
    txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);

    vmxnet3_ring_write_curr_cell(d, &s->txq_descr[qidx].comp_ring, &txcq_descr);

    /* Flush changes in TX descriptor before changing the counter value */
    smp_wmb();

    vmxnet3_inc_tx_completion_counter(s, qidx);
    vmxnet3_trigger_interrupt(s, s->txq_descr[qidx].intr_idx);
}


static void vmxnet3_update_features(VMXNET3State *s)
{
    uint32_t guest_features;
    int rxcso_supported;
    PCIDevice *d = PCI_DEVICE(s);

    guest_features = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem,
                                               devRead.misc.uptFeatures);

    rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM);
    s->rx_vlan_stripping = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXVLAN);
    s->lro_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_LRO);

    VMW_CFPRN("Features configuration: LRO: %d, RXCSUM: %d, VLANSTRIP: %d",
              s->lro_supported, rxcso_supported,
              s->rx_vlan_stripping);
    if (s->peer_has_vhdr) {
        qemu_set_offload(qemu_get_queue(s->nic)->peer,
                         rxcso_supported,
                         s->lro_supported,
                         s->lro_supported,
                         0,
                         0);
    }
}


vmxnet3_pop_next_tx_descr(VMXNET3State *s,
                          int qidx,
                          struct Vmxnet3_TxDesc *txd,
                          uint32_t *descr_idx)
{
    Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring;
    PCIDevice *d = PCI_DEVICE(s);

    vmxnet3_ring_read_curr_cell(d, ring, txd);
    if (txd->gen == vmxnet3_ring_curr_gen(ring)) {
        /* Only read after generation field verification */
        smp_rmb();
        /* Re-read to be sure we got the latest version */
        vmxnet3_ring_read_curr_cell(d, ring, txd);
        VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring);
        *descr_idx = vmxnet3_ring_curr_cell_idx(ring);
        vmxnet3_inc_tx_consumption_counter(s, qidx);
        return true;
    }

    return false;
}


bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc)
{
    assert(pkt);

    if (!pkt->has_virt_hdr &&
        pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
        net_tx_pkt_do_sw_csum(pkt);
    }

    /*
     * Since underlying infrastructure does not support IP datagrams longer
     * than 64K we should drop such packets and don't even try to send
     */
    if (VIRTIO_NET_HDR_GSO_NONE != pkt->virt_hdr.gso_type) {
        if (pkt->payload_len >
            ETH_MAX_IP_DGRAM_LEN -
            pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len) {
            return false;
        }
    }

    if (pkt->has_virt_hdr ||
        pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) {
        net_tx_pkt_sendv(pkt, nc, pkt->vec,
            pkt->payload_frags + NET_TX_PKT_PL_START_FRAG);
        return true;
    }

    return net_tx_pkt_do_sw_fragmentation(pkt, nc);
}


static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt,
    NetClientState *nc)
{
    struct iovec fragment[NET_MAX_FRAG_SG_LIST];
    size_t fragment_len = 0;
    bool more_frags = false;

    /* some pointers for shorter code */
    void *l2_iov_base, *l3_iov_base;
    size_t l2_iov_len, l3_iov_len;
    int src_idx =  NET_TX_PKT_PL_START_FRAG, dst_idx;
    size_t src_offset = 0;
    size_t fragment_offset = 0;

    l2_iov_base = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base;
    l2_iov_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len;
    l3_iov_base = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base;
    l3_iov_len = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len;

    /* Copy headers */
    fragment[NET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base;
    fragment[NET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len;
    fragment[NET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base;
    fragment[NET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len;

    /* Put as much data as possible and send */
    do {
        fragment_len = net_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset,
            fragment, &dst_idx);

        more_frags = (fragment_offset + fragment_len < pkt->payload_len);

        eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base,
            l3_iov_len, fragment_len, fragment_offset, more_frags);

        eth_fix_ip4_checksum(l3_iov_base, l3_iov_len);

        net_tx_pkt_sendv(pkt, nc, fragment, dst_idx);

        fragment_offset += fragment_len;

    } while (fragment_len && more_frags);

    return true;
}


static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt)
{
    struct iovec *l2_hdr, *l3_hdr;
    size_t bytes_read;
    size_t full_ip6hdr_len;
    uint16_t l3_proto;

    assert(pkt);

    l2_hdr = &pkt->vec[NET_TX_PKT_L2HDR_FRAG];
    l3_hdr = &pkt->vec[NET_TX_PKT_L3HDR_FRAG];

    bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,
                            ETH_MAX_L2_HDR_LEN);
    if (bytes_read < sizeof(struct eth_header)) {
        l2_hdr->iov_len = 0;
        return false;
    }

    l2_hdr->iov_len = sizeof(struct eth_header);
    switch (be16_to_cpu(PKT_GET_ETH_HDR(l2_hdr->iov_base)->h_proto)) {
    case ETH_P_VLAN:
        l2_hdr->iov_len += sizeof(struct vlan_header);
        break;
    case ETH_P_DVLAN:
        l2_hdr->iov_len += 2 * sizeof(struct vlan_header);
        break;
    }

    if (bytes_read < l2_hdr->iov_len) {
        l2_hdr->iov_len = 0;
        l3_hdr->iov_len = 0;
        pkt->packet_type = ETH_PKT_UCAST;
        return false;
    } else {
        l2_hdr->iov_len = ETH_MAX_L2_HDR_LEN;
        l2_hdr->iov_len = eth_get_l2_hdr_length(l2_hdr->iov_base);
        pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base);
    }

    l3_proto = eth_get_l3_proto(l2_hdr, 1, l2_hdr->iov_len);

    switch (l3_proto) {
    case ETH_P_IP:
        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
                                l3_hdr->iov_base, sizeof(struct ip_header));

        if (bytes_read < sizeof(struct ip_header)) {
            l3_hdr->iov_len = 0;
            return false;
        }

        l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base);

        if (l3_hdr->iov_len < sizeof(struct ip_header)) {
            l3_hdr->iov_len = 0;
            return false;
        }

        pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;

        if (IP_HDR_GET_LEN(l3_hdr->iov_base) != sizeof(struct ip_header)) {
            /* copy optional IPv4 header data if any*/
            bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags,
                                    l2_hdr->iov_len + sizeof(struct ip_header),
                                    l3_hdr->iov_base + sizeof(struct ip_header),
                                    l3_hdr->iov_len - sizeof(struct ip_header));
            if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) {
                l3_hdr->iov_len = 0;
                return false;
            }
        }

        break;

    case ETH_P_IPV6:
    {
        eth_ip6_hdr_info hdrinfo;

        if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
                                &hdrinfo)) {
            l3_hdr->iov_len = 0;
            return false;
        }

        pkt->l4proto = hdrinfo.l4proto;
        full_ip6hdr_len = hdrinfo.full_hdr_len;

        if (full_ip6hdr_len > ETH_MAX_IP_DGRAM_LEN) {
            l3_hdr->iov_len = 0;
            return false;
        }

        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
                                l3_hdr->iov_base, full_ip6hdr_len);

        if (bytes_read < full_ip6hdr_len) {
            l3_hdr->iov_len = 0;
            return false;
        } else {
            l3_hdr->iov_len = full_ip6hdr_len;
        }
        break;
    }
    default:
        l3_hdr->iov_len = 0;
        break;
    }

    net_tx_pkt_calculate_hdr_len(pkt);
    return true;
}


static void net_tx_pkt_calculate_hdr_len(struct NetTxPkt *pkt)
{
    pkt->hdr_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len +
        pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len;
}


krb5_error_code ipadb_put_pwd_policy(krb5_context kcontext,
                                     osa_policy_ent_t policy)
{
    return KRB5_PLUGIN_OP_NOTSUPP;
}


rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg)
{
    rpmRC rc;
    rpmVSFlags vsflags = rpmtsVSFlags(ts);
    rpmKeyring keyring = rpmtsGetKeyring(ts, 1);

    rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
    rc = headerVerify(keyring, vsflags, uh, uc, msg);
    rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), uc);
    rpmKeyringFree(keyring);

    return rc;
}


static gboolean grow_buffer (struct bmp_progressive_state *State,
                             GError **error)
{
  guchar *tmp;

  if (State->BufferSize == 0) {
    g_set_error_literal (error,
                         GDK_PIXBUF_ERROR,
                         GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                         _("BMP image has bogus header data"));
    State->read_state = READ_STATE_ERROR;
    return FALSE;
  }

  tmp = g_try_realloc (State->buff, State->BufferSize);

  if (!tmp) {
    g_set_error_literal (error,
                         GDK_PIXBUF_ERROR,
                         GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                         _("Not enough memory to load bitmap image"));
    State->read_state = READ_STATE_ERROR;
    return FALSE;
  }

  State->buff = tmp;
  return TRUE;
}


static void OneLine16(struct bmp_progressive_state *context)
{
	int i;
	guchar *pixels;
	guchar *src;

	if (!context->Header.Negative)
		pixels = (context->pixbuf->pixels +
			  context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
	else
		pixels = (context->pixbuf->pixels +
			  context->pixbuf->rowstride * context->Lines);

	src = context->buff;

	if (context->Compressed == BI_BITFIELDS) {
		int r_lshift, r_rshift;
		int g_lshift, g_rshift;
		int b_lshift, b_rshift;

		r_lshift = 8 - context->r_bits;
		g_lshift = 8 - context->g_bits;
		b_lshift = 8 - context->b_bits;

		r_rshift = context->r_bits - r_lshift;
		g_rshift = context->g_bits - g_lshift;
		b_rshift = context->b_bits - b_lshift;

		for (i = 0; i < context->Header.width; i++) {
			int v, r, g, b;

			v = (int) src[0] | ((int) src[1] << 8);

			r = (v & context->r_mask) >> context->r_shift;
			g = (v & context->g_mask) >> context->g_shift;
			b = (v & context->b_mask) >> context->b_shift;

			*pixels++ = (r << r_lshift) | (r >> r_rshift);
			*pixels++ = (g << g_lshift) | (g >> g_rshift);
			*pixels++ = (b << b_lshift) | (b >> b_rshift);

			src += 2;
		}
	} else
		for (i = 0; i < context->Header.width; i++) {
			int v, r, g, b;

			v = src[0] | (src[1] << 8);

			r = (v >> 10) & 0x1f;
			g = (v >> 5) & 0x1f;
			b = v & 0x1f;

			*pixels++ = (r << 3) | (r >> 2);
			*pixels++ = (g << 3) | (g >> 2);
			*pixels++ = (b << 3) | (b >> 2);

			src += 2;
		}
}


gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
                                 GdkPixbufModulePreparedFunc prepared_func,
				 GdkPixbufModuleUpdatedFunc updated_func,
                                 gpointer user_data,
                                 GError **error)
{
	struct bmp_progressive_state *context;

	context = g_new0(struct bmp_progressive_state, 1);
	context->size_func = size_func;
	context->prepared_func = prepared_func;
	context->updated_func = updated_func;
	context->user_data = user_data;

	context->read_state = READ_STATE_HEADERS;

	context->BufferSize = 26;
	context->BufferPadding = 0;
	context->buff = g_malloc(26);
	context->BufferDone = 0;
	/* 14 for the BitmapFileHeader, 12 for the BitmapImageHeader */

	context->Colormap = NULL;

	context->Lines = 0;

	context->Type = 0;

	memset(&context->Header, 0, sizeof(struct headerpair));
	memset(&context->compr, 0, sizeof(struct bmp_compression_state));

	context->pixbuf = NULL;

	return (gpointer) context;
}


static void OneLine4(struct bmp_progressive_state *context)
{
	gint X;
	guchar *Pixels;

	X = 0;
	if (context->Header.Negative == 0)
		Pixels = (context->pixbuf->pixels +
			  context->pixbuf->rowstride *
			  (context->Header.height - context->Lines - 1));
	else
		Pixels = (context->pixbuf->pixels +
			  context->pixbuf->rowstride *
			  context->Lines);

	while (X < context->Header.width) {
		guchar Pix;

		Pix = context->buff[X / 2];

		Pixels[X * 3 + 0] =
		    context->Colormap[Pix >> 4][2];
		Pixels[X * 3 + 1] =
		    context->Colormap[Pix >> 4][1];
		Pixels[X * 3 + 2] =
		    context->Colormap[Pix >> 4][0];
		X++;
		if (X < context->Header.width) {
			/* Handle the other 4 bit pixel only when there is one */
			Pixels[X * 3 + 0] =
			    context->Colormap[Pix & 15][2];
			Pixels[X * 3 + 1] =
			    context->Colormap[Pix & 15][1];
			Pixels[X * 3 + 2] =
			    context->Colormap[Pix & 15][0];
			X++;
		}
	}

}


_ocsp_resp_verify_direct(gnutls_ocsp_resp_t resp,
			 gnutls_x509_crt_t signercert,
			 unsigned int *verify, unsigned int flags)
{
	gnutls_datum_t sig = { NULL };
	gnutls_datum_t data = { NULL };
	gnutls_pubkey_t pubkey = NULL;
	int sigalg;
	int rc;

	if (resp == NULL || signercert == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	rc = gnutls_ocsp_resp_get_signature_algorithm(resp);
	if (rc < 0) {
		gnutls_assert();
		goto done;
	}
	sigalg = rc;

	rc = _gnutls_x509_get_raw_field2(resp->basicresp, &resp->der, "tbsResponseData", &data);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_pubkey_init(&pubkey);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_pubkey_import_x509(pubkey, signercert, 0);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_ocsp_resp_get_signature(resp, &sig);
	if (rc != GNUTLS_E_SUCCESS) {
		gnutls_assert();
		goto done;
	}

	rc = gnutls_pubkey_verify_data2(pubkey, sigalg, 0, &data, &sig);
	if (rc == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
		gnutls_assert();
		*verify = GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE;
	} else if (rc < 0) {
		gnutls_assert();
		goto done;
	} else
		*verify = 0;

	rc = GNUTLS_E_SUCCESS;

      done:
	gnutls_free(sig.data);
	gnutls_pubkey_deinit(pubkey);

	return rc;
}


gnutls_ocsp_resp_check_crt(gnutls_ocsp_resp_t resp,
			   unsigned int indx, gnutls_x509_crt_t crt)
{
	int ret;
	gnutls_digest_algorithm_t digest;
	gnutls_datum_t rdn_hash = { NULL, 0 }, rserial = {
	NULL, 0};
	gnutls_datum_t cserial = { NULL, 0 };
	gnutls_datum_t dn = { NULL, 0 };
	uint8_t cdn_hash[MAX_HASH_SIZE];
	size_t t, hash_len;

	ret =
	    gnutls_ocsp_resp_get_single(resp, indx, &digest, &rdn_hash,
					NULL, &rserial, NULL, NULL, NULL,
					NULL, NULL);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (rserial.size == 0 || digest == GNUTLS_DIG_UNKNOWN) {
		ret = gnutls_assert_val(GNUTLS_E_OCSP_RESPONSE_ERROR);
		goto cleanup;
	}

	hash_len = _gnutls_hash_get_algo_len(hash_to_entry(digest));
	if (hash_len != rdn_hash.size) {
		ret = gnutls_assert_val(GNUTLS_E_OCSP_RESPONSE_ERROR);
		goto cleanup;
	}

	cserial.size = rserial.size;
	cserial.data = gnutls_malloc(cserial.size);
	if (cserial.data == NULL) {
		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
		goto cleanup;
	}

	t = cserial.size;
	ret = gnutls_x509_crt_get_serial(crt, cserial.data, &t);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}
	cserial.size = t;

	if (rserial.size != cserial.size
	    || memcmp(cserial.data, rserial.data, rserial.size) != 0) {
		ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
		gnutls_assert();
		goto cleanup;
	}

	ret = gnutls_x509_crt_get_raw_issuer_dn(crt, &dn);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = _gnutls_hash_fast(digest, dn.data, dn.size, cdn_hash);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (memcmp(cdn_hash, rdn_hash.data, hash_len) != 0) {
		ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
		gnutls_assert();
		goto cleanup;
	}

	ret = 0;

      cleanup:
	gnutls_free(rdn_hash.data);
	gnutls_free(rserial.data);
	gnutls_free(cserial.data);
	gnutls_free(dn.data);

	return ret;
}


static inline unsigned int vstatus_to_ocsp_status(unsigned int status)
{
	unsigned int ostatus;

	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
		ostatus = GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM;
	else if (status & GNUTLS_CERT_NOT_ACTIVATED)
		ostatus = GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED;
	else if (status & GNUTLS_CERT_EXPIRED)
		ostatus = GNUTLS_OCSP_VERIFY_CERT_EXPIRED;
	else
		ostatus = GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER;

	return ostatus;
}


gnutls_ocsp_resp_verify(gnutls_ocsp_resp_t resp,
			gnutls_x509_trust_list_t trustlist,
			unsigned int *verify, unsigned int flags)
{
	gnutls_x509_crt_t signercert = NULL;
	int rc;

	/* Algorithm:
	   1. Find signer cert.
	   1a. Search in OCSP response Certificate field for responderID.
	   1b. Verify that signer cert is trusted.
	   2a. It is in trustlist?
	   2b. It has OCSP key usage and directly signed by a CA in trustlist?
	   3. Verify signature of Basic Response using public key from signer cert.
	 */

	signercert = find_signercert(resp);
	if (!signercert) {
		gnutls_datum_t dn;

		rc = gnutls_ocsp_resp_get_responder_raw_id(resp, GNUTLS_OCSP_RESP_ID_DN, &dn);
		if (rc < 0) {
			gnutls_assert();
			*verify = GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND;
			rc = GNUTLS_E_SUCCESS;
			goto done;
		}

		rc = gnutls_x509_trust_list_get_issuer_by_dn(trustlist, &dn, &signercert, 0);
		gnutls_free(dn.data);

		if (rc < 0) {
			gnutls_assert();
			*verify = GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND;
			rc = GNUTLS_E_SUCCESS;
			goto done;
		}
	} else {
		/* Either the signer is directly trusted (i.e., in trustlist) or it
		   is directly signed by something in trustlist and has proper OCSP
		   extkeyusage. */
		rc = _gnutls_trustlist_inlist(trustlist, signercert);
		if (rc == 0) {
			/* not in trustlist, need to verify signature and bits */
			unsigned vtmp;
			gnutls_typed_vdata_st vdata;

			vdata.type = GNUTLS_DT_KEY_PURPOSE_OID;
			vdata.data = (void*)GNUTLS_KP_OCSP_SIGNING;
			vdata.size = 0;

			gnutls_assert();

			rc = gnutls_x509_trust_list_verify_crt2(trustlist,
								&signercert, 1,
								&vdata, 1,
								0, &vtmp, NULL);
			if (rc != GNUTLS_E_SUCCESS) {
				gnutls_assert();
				goto done;
			}

			if (vtmp != 0) {
				*verify = vstatus_to_ocsp_status(vtmp);
				gnutls_assert();
				rc = GNUTLS_E_SUCCESS;
				goto done;
			}
		}
	}

	rc = check_ocsp_purpose(signercert);
	if (rc < 0) {
		gnutls_assert();
		*verify = GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR;
		rc = GNUTLS_E_SUCCESS;
		goto done;
	}

	rc = _ocsp_resp_verify_direct(resp, signercert, verify, flags);

      done:
	gnutls_x509_crt_deinit(signercert);

	return rc;
}


static OPJ_BOOL opj_pi_next_lrcp(opj_pi_iterator_t * pi) {
	opj_pi_comp_t *comp = NULL;
	opj_pi_resolution_t *res = NULL;
	OPJ_UINT32 index = 0;

	if (!pi->first) {
		comp = &pi->comps[pi->compno];
		res = &comp->resolutions[pi->resno];
		goto LABEL_SKIP;
	} else {
		pi->first = 0;
	}

	for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) {
		for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1;
		pi->resno++) {
			for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) {
				comp = &pi->comps[pi->compno];
				if (pi->resno >= comp->numresolutions) {
					continue;
				}
				res = &comp->resolutions[pi->resno];
				if (!pi->tp_on){
					pi->poc.precno1 = res->pw * res->ph;
				}
				for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) {
					index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p;
					if (!pi->include[index]) {
						pi->include[index] = 1;
						return OPJ_TRUE;
					}
LABEL_SKIP:;
				}
			}
		}
	}

	return OPJ_FALSE;
}


OPJ_BOOL opj_pi_next(opj_pi_iterator_t * pi) {
	switch (pi->poc.prg) {
		case OPJ_LRCP:
			return opj_pi_next_lrcp(pi);
		case OPJ_RLCP:
			return opj_pi_next_rlcp(pi);
		case OPJ_RPCL:
			return opj_pi_next_rpcl(pi);
		case OPJ_PCRL:
			return opj_pi_next_pcrl(pi);
		case OPJ_CPRL:
			return opj_pi_next_cprl(pi);
		case OPJ_PROG_UNKNOWN:
			return OPJ_FALSE;
	}

	return OPJ_FALSE;
}


local int decode(struct state *s, const struct huffman *h)
{
    int len;            /* current number of bits in code */
    int code;           /* len bits being decoded */
    int first;          /* first code of length len */
    int count;          /* number of codes of length len */
    int index;          /* index of first code of length len in symbol table */

    code = first = index = 0;
    for (len = 1; len <= MAXBITS; len++) {
        code |= bits(s, 1);             /* get next bit */
        count = h->count[len];
        if (code - count < first)       /* if length len, return symbol */
            return h->symbol[index + (code - first)];
        index += count;                 /* else update for next length */
        first += count;
        first <<= 1;
        code <<= 1;
    }
    return -10;                         /* ran out of codes */
}


void stripLine(string &line)
{
  string::size_type pos=line.find_first_of("\r\n");
  if(pos!=string::npos) {
    line.resize(pos);
  }
}


void parseService(const string &descr, ServiceTuple &st)
{
  if(descr.empty())
    throw PDNSException("Unable to parse '"+descr+"' as a service");

  vector<string> parts;
  stringtok(parts, descr, ":");

  if(descr[0]=='[') {
    parseService6(descr, st);
  }
  else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) {
    st.host=descr;
  }
  else {
    parseService4(descr, st);
  }
}


string itoa(int i)
{
  ostringstream o;
  o<<i;
  return o.str();
}


bool chopOffDotted(string &domain)
{
  if(domain.empty() || (domain.size()==1 && domain[0]=='.'))
    return false;

  bool escaped = false;
  const string::size_type domainLen = domain.length();
  for (size_t fdot = 0; fdot < domainLen; fdot++)
  {
    if (domain[fdot] == '.' && !escaped) {
      if (fdot==domain.size()-1) {
        domain=".";
      }
      else {
        string::size_type remain = domainLen - (fdot + 1);
        char tmp[remain];
        memcpy(tmp, domain.c_str()+fdot+1, remain);
        domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)
      }
      return true;
    }
    else if (domain[fdot] == '\\' && !escaped) {
      escaped = true;
    }
    else {
      escaped = false;
    }
  }

  return false;
}


void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs, size_t& wirelength)
{
  if(recurs > 100) // the forward reference-check below should make this test 100% obsolete
    throw MOADNSException("Loop");

  int pos = frompos;
  // it is tempting to call reserve on ret, but it turns out it creates a malloc/free storm in the loop
  for(;;) {
    unsigned char labellen=content.at(frompos++);
    wirelength++;
    if (wirelength > 255) {
      throw MOADNSException("Overly long DNS name ("+lexical_cast<string>(wirelength)+")");
    }

    if(!labellen) {
      if(ret.empty())
              ret.append(1,'.');
      break;
    }
    else if((labellen & 0xc0) == 0xc0) {
      uint16_t offset=256*(labellen & ~0xc0) + (unsigned int)content.at(frompos++) - sizeof(dnsheader);
      //        cout<<"This is an offset, need to go to: "<<offset<<endl;

      if(offset >= pos)
        throw MOADNSException("forward reference during label decompression");
      /* the compression pointer does not count into the wire length */
      return getLabelFromContent(content, offset, ret, ++recurs, --wirelength);
    }
    else if(labellen > 63)
      throw MOADNSException("Overly long label during label decompression ("+lexical_cast<string>((unsigned int)labellen)+")");
    else {
      if (wirelength + labellen > 255) {
        throw MOADNSException("Overly long DNS name ("+lexical_cast<string>(wirelength)+")");
      }
      wirelength += labellen;
      // XXX FIXME THIS MIGHT BE VERY SLOW!
      for(string::size_type n = 0 ; n < labellen; ++n, frompos++) {
        if(content.at(frompos)=='.' || content.at(frompos)=='\\') {
          ret.append(1, '\\');
          ret.append(1, content[frompos]);
        }
        else if(content.at(frompos)==' ') {
          ret+="\\032";
        }
        else
          ret.append(1, content[frompos]);
      }
      ret.append(1,'.');
    }
    if (ret.length() > 1024)
      throw MOADNSException("Total name too long");
  }
}


time_t DTime::time()
{
  return d_set.tv_sec;
}


string dotConcat(const std::string& a, const std::string &b)
{
  if(a.empty() || b.empty())
    return a+b;
  else
    return a+"."+b;
}


bool IpToU32(const string &str, uint32_t *ip)
{
  if(str.empty()) {
    *ip=0;
    return true;
  }

  struct in_addr inp;
  if(Utility::inet_aton(str.c_str(), &inp)) {
    *ip=inp.s_addr;
    return true;
  }
  return false;
}


bool MYSQL_BIN_LOG::write(Log_event *event_info)
{
  THD *thd= event_info->thd;
  bool error= 1;
  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
  binlog_cache_data *cache_data= 0;
  bool is_trans_cache= FALSE;

  if (thd->binlog_evt_union.do_union)
  {
    /*
      In Stored function; Remember that function call caused an update.
      We will log the function call to the binary log on function exit
    */
    thd->binlog_evt_union.unioned_events= TRUE;
    thd->binlog_evt_union.unioned_events_trans |=
      event_info->use_trans_cache();
    DBUG_RETURN(0);
  }

  /*
    We only end the statement if we are in a top-level statement.  If
    we are inside a stored function, we do not end the statement since
    this will close all tables on the slave.
  */
  bool const end_stmt=
    thd->locked_tables_mode && thd->lex->requires_prelocking();
  if (thd->binlog_flush_pending_rows_event(end_stmt,
                                           event_info->use_trans_cache()))
    DBUG_RETURN(error);

  /*
     In most cases this is only called if 'is_open()' is true; in fact this is
     mostly called if is_open() *was* true a few instructions before, but it
     could have changed since.
  */
  if (likely(is_open()))
  {
#ifdef HAVE_REPLICATION
    /*
      In the future we need to add to the following if tests like
      "do the involved tables match (to be implemented)
      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
    */
    const char *local_db= event_info->get_db();
    if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
	(thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT &&
         thd->lex->sql_command != SQLCOM_SAVEPOINT &&
         !binlog_filter->db_ok(local_db)))
      DBUG_RETURN(0);
#endif /* HAVE_REPLICATION */

    IO_CACHE *file= NULL;

    if (event_info->use_direct_logging())
    {
      file= &log_file;
      mysql_mutex_lock(&LOCK_log);
    }
    else
    {
      if (thd->binlog_setup_trx_data())
        goto err;

      binlog_cache_mngr *const cache_mngr=
        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);

      is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
      file= cache_mngr->get_binlog_cache_log(is_trans_cache);
      cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);

      if (thd->lex->stmt_accessed_non_trans_temp_table())
        cache_data->set_changes_to_non_trans_temp_table();

      thd->binlog_start_trans_and_stmt();
    }
    DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));

    /*
       No check for auto events flag here - this write method should
       never be called if auto-events are enabled.

       Write first log events which describe the 'run environment'
       of the SQL command. If row-based binlogging, Insert_id, Rand
       and other kind of "setting context" events are not needed.
    */
    if (thd)
    {
      if (!thd->is_current_stmt_binlog_format_row())
      {
        if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
        {
          Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
                             thd->first_successful_insert_id_in_prev_stmt_for_binlog);
          if (e.write(file))
            goto err;
        }
        if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
        {
          DBUG_PRINT("info",("number of auto_inc intervals: %u",
                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
                             nb_elements()));
          Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
                             minimum());
          if (e.write(file))
            goto err;
        }
        if (thd->rand_used)
        {
          Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
          if (e.write(file))
            goto err;
        }
        if (thd->user_var_events.elements)
        {
          for (uint i= 0; i < thd->user_var_events.elements; i++)
          {
            BINLOG_USER_VAR_EVENT *user_var_event;
            get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);

            /* setting flags for user var log event */
            uchar flags= User_var_log_event::UNDEF_F;
            if (user_var_event->unsigned_flag)
              flags|= User_var_log_event::UNSIGNED_F;

            User_var_log_event e(thd, user_var_event->user_var_event->name.str,
                                 user_var_event->user_var_event->name.length,
                                 user_var_event->value,
                                 user_var_event->length,
                                 user_var_event->type,
                                 user_var_event->charset_number,
                                 flags);
            if (e.write(file))
              goto err;
          }
        }
      }
    }

    /*
      Write the event.
    */
    if (event_info->write(file) ||
        DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
      goto err;

    error= 0;
err:
    if (event_info->use_direct_logging())
    {
      if (!error)
      {
        bool synced;
        if ((error= flush_and_sync(&synced)))
        {
          mysql_mutex_unlock(&LOCK_log);
        }
        else if ((error= RUN_HOOK(binlog_storage, after_flush,
                 (thd, log_file_name, file->pos_in_file, synced))))
        {
          sql_print_error("Failed to run 'after_flush' hooks");
          mysql_mutex_unlock(&LOCK_log);
        }
        else
        {
          bool check_purge;
          signal_update();
          error= rotate(false, &check_purge);
          mysql_mutex_unlock(&LOCK_log);
          if (!error && check_purge)
            purge();
        }
      }
      else
      {
        mysql_mutex_unlock(&LOCK_log);
      }
    }

    if (error)
    {
      set_write_error(thd, is_trans_cache);
      if (check_write_error(thd) && cache_data &&
          stmt_has_updated_non_trans_table(thd))
        cache_data->set_incident();
    }
  }

  DBUG_RETURN(error);
}


void MYSQL_QUERY_LOG::reopen_file()
{
  char *save_name;

  DBUG_ENTER("MYSQL_LOG::reopen_file");
  if (!is_open())
  {
    DBUG_PRINT("info",("log is closed"));
    DBUG_VOID_RETURN;
  }

  mysql_mutex_lock(&LOCK_log);

  save_name= name;
  name= 0;				// Don't free name
  close(LOG_CLOSE_TO_BE_OPENED);

  /*
     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
  */

  open(
#ifdef HAVE_PSI_INTERFACE
       m_log_file_key,
#endif
       save_name, log_type, 0, io_cache_type);
  my_free(save_name);

  mysql_mutex_unlock(&LOCK_log);

  DBUG_VOID_RETURN;
}


void init_sql_statement_names()
{
  static LEX_CSTRING empty= { C_STRING_WITH_LEN("") };

  char *first_com= (char*) offsetof(STATUS_VAR, com_stat[0]);
  char *last_com= (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_END]);
  int record_size= (char*) offsetof(STATUS_VAR, com_stat[1])
                   - (char*) offsetof(STATUS_VAR, com_stat[0]);
  char *ptr;
  uint i;
  uint com_index;

  for (i= 0; i < ((uint) SQLCOM_END + 1); i++)
    sql_statement_names[i]= empty;

  SHOW_VAR *var= &com_status_vars[0];
  while (var->name != NULL)
  {
    ptr= var->value;
    if ((first_com <= ptr) && (ptr <= last_com))
    {
      com_index= ((int)(ptr - first_com))/record_size;
      DBUG_ASSERT(com_index < (uint) SQLCOM_END);
      sql_statement_names[com_index].str= var->name;
      /* TODO: Change SHOW_VAR::name to a LEX_STRING, to avoid strlen() */
      sql_statement_names[com_index].length= strlen(var->name);
    }
    var++;
  }

  DBUG_ASSERT(strcmp(sql_statement_names[(uint) SQLCOM_SELECT].str, "select") == 0);
  DBUG_ASSERT(strcmp(sql_statement_names[(uint) SQLCOM_SIGNAL].str, "signal") == 0);

  sql_statement_names[(uint) SQLCOM_END].str= "error";
}


  void truncate(my_off_t pos)
  {
    DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
    if (pending())
    {
      delete pending();
      set_pending(0);
    }
    reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
    cache_log.end_of_file= saved_max_binlog_cache_size;
  }


bool LOGGER::flush_slow_log()
{
  /*
    Now we lock logger, as nobody should be able to use logging routines while
    log tables are closed
  */
  logger.lock_exclusive();

  /* Reopen slow log file */
  if (opt_slow_log)
    file_log_handler->get_mysql_slow_log()->reopen_file();

  /* End of log flush */
  logger.unlock();

  return 0;
}


static bool read_init_file(char *file_name)
{
  MYSQL_FILE *file;
  DBUG_ENTER("read_init_file");
  DBUG_PRINT("enter",("name: %s",file_name));
  if (!(file= mysql_file_fopen(key_file_init, file_name,
                               O_RDONLY, MYF(MY_WME))))
    DBUG_RETURN(TRUE);
  bootstrap(file);
  mysql_file_fclose(file, MYF(MY_WME));
  DBUG_RETURN(FALSE);
}


bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
{
  return (thd->binlog_evt_union.do_union &&
          query_id_param >= thd->binlog_evt_union.first_query_id);
}


bool general_log_write(THD *thd, enum enum_server_command command,
                       const char *query, uint query_length)
{
  /* Write the message to the log if we want to log this king of commands */
  if (logger.log_command(thd, command))
    return logger.general_log_write(thd, command, query, query_length);

  return FALSE;
}


int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
{
  int error;
  char *to_purge_if_included= NULL;
  DBUG_ENTER("purge_first_log");

  DBUG_ASSERT(is_open());
  DBUG_ASSERT(rli->slave_running == 1);
  DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));

  mysql_mutex_lock(&LOCK_index);
  to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));

  /*
    Read the next log file name from the index file and pass it back to
    the caller.
  */
  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
     (error=find_next_log(&rli->linfo, 0)))
  {
    char buff[22];
    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
                    error,
                    llstr(rli->linfo.index_file_offset,buff),
                    rli->event_relay_log_name,
                    included);
    goto err;
  }

  /*
    Reset rli's coordinates to the current log.
  */
  rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
  strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
	  sizeof(rli->event_relay_log_name)-1);

  /*
    If we removed the rli->group_relay_log_name file,
    we must update the rli->group* coordinates, otherwise do not touch it as the
    group's execution is not finished (e.g. COMMIT not executed)
  */
  if (included)
  {
    rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
    strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
            sizeof(rli->group_relay_log_name)-1);
    rli->notify_group_relay_log_name_update();
  }

  /* Store where we are in the new file for the execution thread */
  flush_relay_log_info(rli);

  DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););

  mysql_mutex_lock(&rli->log_space_lock);
  rli->relay_log.purge_logs(to_purge_if_included, included,
                            0, 0, &rli->log_space_total);
  mysql_mutex_unlock(&rli->log_space_lock);

  /*
    Ok to broadcast after the critical region as there is no risk of
    the mutex being destroyed by this thread later - this helps save
    context switches
  */
  mysql_cond_broadcast(&rli->log_space_cond);

  /*
   * Need to update the log pos because purge logs has been called
   * after fetching initially the log pos at the begining of the method.
   */
  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
  {
    char buff[22];
    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
                    error,
                    llstr(rli->linfo.index_file_offset,buff),
                    rli->group_relay_log_name,
                    included);
    goto err;
  }

  /* If included was passed, rli->linfo should be the first entry. */
  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);

err:
  my_free(to_purge_if_included);
  mysql_mutex_unlock(&LOCK_index);
  DBUG_RETURN(error);
}


static bool update_cached_long_query_time(sys_var *self, THD *thd,
                                          enum_var_type type)
{
  if (type == OPT_SESSION)
    thd->variables.long_query_time=
      double2ulonglong(thd->variables.long_query_time_double * 1e6);
  else
    global_system_variables.long_query_time=
      double2ulonglong(global_system_variables.long_query_time_double * 1e6);
  return false;
}


int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
{
  if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
    return LOG_INFO_IO;

  // now update offsets in index file for running threads
  if (need_update_threads)
    adjust_linfo_offsets(log_info->index_file_start_offset);
  return 0;
}


int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
{
  int error;
  char to_log[FN_REFLEN];
  LOG_INFO log_info;
  MY_STAT stat_area;
  THD *thd= current_thd;

  DBUG_ENTER("purge_logs_before_date");

  mysql_mutex_lock(&LOCK_index);
  to_log[0]= 0;

  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
    goto err;

  while (strcmp(log_file_name, log_info.log_file_name) &&
	 !is_active(log_info.log_file_name) &&
         !log_in_use(log_info.log_file_name))
  {
    if (!mysql_file_stat(m_key_file_log,
                         log_info.log_file_name, &stat_area, MYF(0)))
    {
      if (my_errno == ENOENT)
      {
        /*
          It's not fatal if we can't stat a log file that does not exist.
        */
        my_errno= 0;
      }
      else
      {
        /*
          Other than ENOENT are fatal
        */
        if (thd)
        {
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                              ER_BINLOG_PURGE_FATAL_ERR,
                              "a problem with getting info on being purged %s; "
                              "consider examining correspondence "
                              "of your binlog index file "
                              "to the actual binlog files",
                              log_info.log_file_name);
        }
        else
        {
          sql_print_information("Failed to delete log file '%s'",
                                log_info.log_file_name);
        }
        error= LOG_INFO_FATAL;
        goto err;
      }
    }
    else
    {
      if (stat_area.st_mtime < purge_time)
        strmake(to_log,
                log_info.log_file_name,
                sizeof(log_info.log_file_name) - 1);
      else
        break;
    }
    if (find_next_log(&log_info, 0))
      break;
  }

  error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);

err:
  mysql_mutex_unlock(&LOCK_index);
  DBUG_RETURN(error);
}


void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
{
  /*
    We need to take locks, otherwise this may happen:
    new_file() is called, calls open(old_max_size), then before open() starts,
    set_max_size() sets max_size to max_size_arg, then open() starts and
    uses the old_max_size argument, so max_size_arg has been overwritten and
    it's like if the SET command was never run.
  */
  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
  mysql_mutex_lock(&LOCK_log);
  if (is_open())
    max_size= max_size_arg;
  mysql_mutex_unlock(&LOCK_log);
  DBUG_VOID_RETURN;
}


static bool fix_net_write_timeout(sys_var *self, THD *thd, enum_var_type type)
{
  if (type != OPT_GLOBAL)
    my_net_set_write_timeout(&thd->net, thd->variables.net_write_timeout);
  return false;
}


int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
{
  Log_event  *ev;
  HASH xids;
  MEM_ROOT mem_root;

  if (! fdle->is_valid() ||
      my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
                   sizeof(my_xid), 0, 0, MYF(0)))
    goto err1;

  init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);

  fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error

  while ((ev= Log_event::read_log_event(log,0,fdle)) && ev->is_valid())
  {
    if (ev->get_type_code() == XID_EVENT)
    {
      Xid_log_event *xev=(Xid_log_event *)ev;
      uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
                                      sizeof(xev->xid));
      if (!x || my_hash_insert(&xids, x))
        goto err2;
    }
    delete ev;
  }

  if (ha_recover(&xids))
    goto err2;

  free_root(&mem_root, MYF(0));
  my_hash_free(&xids);
  return 0;

err2:
  free_root(&mem_root, MYF(0));
  my_hash_free(&xids);
err1:
  sql_print_error("Crash recovery failed. Either correct the problem "
                  "(if it's, for example, out of memory error) and restart, "
                  "or delete (or rename) binary log and start mysqld with "
                  "--tc-heuristic-recover={commit|rollback}");
  return 1;
}


stmt_has_updated_trans_table(Ha_trx_info* ha_list)
{
  Ha_trx_info *ha_info;
  for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
  {
    if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
      return (TRUE);
  }
  return (FALSE);
}


static bool fix_binlog_format_after_update(sys_var *self, THD *thd,
                                           enum_var_type type)
{
  if (type == OPT_SESSION)
    thd->reset_current_stmt_binlog_format_row();
  return false;
}


int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
                       const char *table_name, bool check_if_opened)
{
  if (db_len == 5 &&
      !(lower_case_table_names ?
        my_strcasecmp(system_charset_info, db, "mysql") :
        strcmp(db, "mysql")))
  {
    if (table_name_len == 11 && !(lower_case_table_names ?
                                  my_strcasecmp(system_charset_info,
                                                table_name, "general_log") :
                                  strcmp(table_name, "general_log")))
    {
      if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL))
        return QUERY_LOG_GENERAL;
      return 0;
    }

    if (table_name_len == 8 && !(lower_case_table_names ?
      my_strcasecmp(system_charset_info, table_name, "slow_log") :
      strcmp(table_name, "slow_log")))
    {
      if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_SLOW))
        return QUERY_LOG_SLOW;
      return 0;
    }
  }
  return 0;
}


void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
{
  uint dir_len = dirname_length(log_file_name);
  if (dir_len >= FN_REFLEN)
    dir_len=FN_REFLEN-1;
  strnmov(buf, log_file_name, dir_len);
  strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
}


  void restore_prev_position()
  {
    truncate(before_stmt_pos);
  }


void MYSQL_LOG::init(enum_log_type log_type_arg,
                     enum cache_type io_cache_type_arg)
{
  DBUG_ENTER("MYSQL_LOG::init");
  log_type= log_type_arg;
  io_cache_type= io_cache_type_arg;
  DBUG_PRINT("info",("log_type: %d", log_type));
  DBUG_VOID_RETURN;
}


static bool fix_thd_mem_root(sys_var *self, THD *thd, enum_var_type type)
{
  if (type != OPT_GLOBAL)
    reset_root_defaults(thd->mem_root,
                        thd->variables.query_alloc_block_size,
                        thd->variables.query_prealloc_size);
  return false;
}


static void print_help()
{
  MEM_ROOT mem_root;
  init_alloc_root(&mem_root, 4096, 4096);

  pop_dynamic(&all_options);
  sys_var_add_options(&all_options, sys_var::PARSE_EARLY);
  add_plugin_options(&all_options, &mem_root);
  sort_dynamic(&all_options, (qsort_cmp) option_cmp);
  add_terminator(&all_options);

  my_print_help((my_option*) all_options.buffer);
  my_print_variables((my_option*) all_options.buffer);

  free_root(&mem_root, MYF(0));
  delete_dynamic(&all_options);
}


  Rows_log_event *pending() const
  {
    return m_pending;
  }


static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
			 int line)
{
  int err;
  char const *what;

  switch (mode) {
  case CRYPTO_LOCK|CRYPTO_READ:
    what = "read lock";
    err= mysql_rwlock_rdlock(&lock->lock);
    break;
  case CRYPTO_LOCK|CRYPTO_WRITE:
    what = "write lock";
    err= mysql_rwlock_wrlock(&lock->lock);
    break;
  case CRYPTO_UNLOCK|CRYPTO_READ:
  case CRYPTO_UNLOCK|CRYPTO_WRITE:
    what = "unlock";
    err= mysql_rwlock_unlock(&lock->lock);
    break;
  default:
    /* Unknown locking mode. */
    sql_print_error("Fatal: OpenSSL interface problem (mode=0x%x)", mode);
    abort();
  }
  if (err)
  {
    sql_print_error("Fatal: can't %s OpenSSL lock", what);
    abort();
  }
}


int TC_LOG_MMAP::recover()
{
  HASH xids;
  PAGE *p=pages, *end_p=pages+npages;

  if (memcmp(data, tc_log_magic, sizeof(tc_log_magic)))
  {
    sql_print_error("Bad magic header in tc log");
    goto err1;
  }

  /*
    the first byte after magic signature is set to current
    number of storage engines on startup
  */
  if (data[sizeof(tc_log_magic)] != total_ha_2pc)
  {
    sql_print_error("Recovery failed! You must enable "
                    "exactly %d storage engines that support "
                    "two-phase commit protocol",
                    data[sizeof(tc_log_magic)]);
    goto err1;
  }

  if (my_hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
                   sizeof(my_xid), 0, 0, MYF(0)))
    goto err1;

  for ( ; p < end_p ; p++)
  {
    for (my_xid *x=p->start; x < p->end; x++)
      if (*x && my_hash_insert(&xids, (uchar *)x))
        goto err2; // OOM
  }

  if (ha_recover(&xids))
    goto err2;

  my_hash_free(&xids);
  bzero(data, (size_t)file_length);
  return 0;

err2:
  my_hash_free(&xids);
err1:
  sql_print_error("Crash recovery failed. Either correct the problem "
                  "(if it's, for example, out of memory error) and restart, "
                  "or delete tc log and start mysqld with "
                  "--tc-heuristic-recover={commit|rollback}");
  return 1;
}


void LOGGER::init_log_tables()
{
  if (!table_log_handler)
    table_log_handler= new Log_to_csv_event_handler;

  if (!is_log_tables_initialized &&
      !table_log_handler->init() && !file_log_handler->init())
    is_log_tables_initialized= TRUE;
}


static bool check_collation_not_null(sys_var *self, THD *thd, set_var *var)
{
  if (!var->value)
    return false;

  char buff[STRING_BUFFER_USUAL_SIZE];
  if (var->value->result_type() == STRING_RESULT)
  {
    String str(buff, sizeof(buff), system_charset_info), *res;
    if (!(res= var->value->val_str(&str)))
      var->save_result.ptr= NULL;
    else if (!(var->save_result.ptr= get_charset_by_name(res->c_ptr(), MYF(0))))
    {
      ErrConvString err(res);
      my_error(ER_UNKNOWN_COLLATION, MYF(0), err.ptr());
      return true;
    }
  }
  else // INT_RESULT
  {
    int csno= (int)var->value->val_int();
    if (!(var->save_result.ptr= get_charset(csno, MYF(0))))
    {
      my_error(ER_UNKNOWN_COLLATION, MYF(0), llstr(csno, buff));
      return true;
    }
  }
  return check_not_null(self, thd, var);
}


void refresh_status(THD *thd)
{
  mysql_mutex_lock(&LOCK_status);

  /* Add thread's status variabes to global status */
  add_to_status(&global_status_var, &thd->status_var);

  /* Reset thread's status variables */
  bzero((uchar*) &thd->status_var, sizeof(thd->status_var));

  /* Reset some global variables */
  reset_status_vars();

  /* Reset the counters of all key caches (default and named). */
  process_key_caches(reset_key_cache_counters);
  flush_status_time= time((time_t*) 0);
  mysql_mutex_unlock(&LOCK_status);

  /*
    Set max_used_connections to the number of currently open
    connections.  Lock LOCK_thread_count out of LOCK_status to avoid
    deadlocks.  Status reset becomes not atomic, but status data is
    not exact anyway.
  */
  mysql_mutex_lock(&LOCK_thread_count);
  max_used_connections= thread_count-delayed_insert_threads;
  mysql_mutex_unlock(&LOCK_thread_count);
}


bool Log_to_csv_event_handler::
  log_general(THD *thd, time_t event_time, const char *user_host,
              uint user_host_len, int thread_id,
              const char *command_type, uint command_type_len,
              const char *sql_text, uint sql_text_len,
              CHARSET_INFO *client_cs)
{
  TABLE_LIST table_list;
  TABLE *table;
  bool result= TRUE;
  bool need_close= FALSE;
  bool need_pop= FALSE;
  bool need_rnd_end= FALSE;
  uint field_index;
  Silence_log_table_errors error_handler;
  Open_tables_backup open_tables_backup;
  ulonglong save_thd_options;
  bool save_time_zone_used;

  /*
    CSV uses TIME_to_timestamp() internally if table needs to be repaired
    which will set thd->time_zone_used
  */
  save_time_zone_used= thd->time_zone_used;

  save_thd_options= thd->variables.option_bits;
  thd->variables.option_bits&= ~OPTION_BIN_LOG;

  table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
                            GENERAL_LOG_NAME.str, GENERAL_LOG_NAME.length,
                            GENERAL_LOG_NAME.str,
                            TL_WRITE_CONCURRENT_INSERT);

  /*
    1) open_log_table generates an error of the
    table can not be opened or is corrupted.
    2) "INSERT INTO general_log" can generate warning sometimes.

    Suppress these warnings and errors, they can't be dealt with
    properly anyway.

    QQ: this problem needs to be studied in more detail.
    Comment this 2 lines and run "cast.test" to see what's happening.
  */
  thd->push_internal_handler(& error_handler);
  need_pop= TRUE;

  if (!(table= open_log_table(thd, &table_list, &open_tables_backup)))
    goto err;

  need_close= TRUE;

  if (table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
      table->file->ha_rnd_init(0))
    goto err;

  need_rnd_end= TRUE;

  /* Honor next number columns if present */
  table->next_number_field= table->found_next_number_field;

  /*
    NOTE: we do not call restore_record() here, as all fields are
    filled by the Logger (=> no need to load default ones).
  */

  /*
    We do not set a value for table->field[0], as it will use
    default value (which is CURRENT_TIMESTAMP).
  */

  /* check that all columns exist */
  if (table->s->fields < 6)
    goto err;

  DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP);

  ((Field_timestamp*) table->field[0])->store_timestamp((my_time_t)
                                                        event_time);

  /* do a write */
  if (table->field[1]->store(user_host, user_host_len, client_cs) ||
      table->field[2]->store((longlong) thread_id, TRUE) ||
      table->field[3]->store((longlong) server_id, TRUE) ||
      table->field[4]->store(command_type, command_type_len, client_cs))
    goto err;

  /*
    A positive return value in store() means truncation.
    Still logging a message in the log in this case.
  */
  table->field[5]->flags|= FIELDFLAG_HEX_ESCAPE;
  if (table->field[5]->store(sql_text, sql_text_len, client_cs) < 0)
    goto err;

  /* mark all fields as not null */
  table->field[1]->set_notnull();
  table->field[2]->set_notnull();
  table->field[3]->set_notnull();
  table->field[4]->set_notnull();
  table->field[5]->set_notnull();

  /* Set any extra columns to their default values */
  for (field_index= 6 ; field_index < table->s->fields ; field_index++)
  {
    table->field[field_index]->set_default();
  }

  /* log table entries are not replicated */
  if (table->file->ha_write_row(table->record[0]))
    goto err;

  result= FALSE;

err:
  if (result && !thd->killed)
    sql_print_error("Failed to write to mysql.general_log: %s",
                    error_handler.message());

  if (need_rnd_end)
  {
    table->file->ha_rnd_end();
    table->file->ha_release_auto_increment();
  }
  if (need_pop)
    thd->pop_internal_handler();
  if (need_close)
    close_log_table(thd, &open_tables_backup);

  thd->variables.option_bits= save_thd_options;
  thd->time_zone_used= save_time_zone_used;
  return result;
}


int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
{
  mysql_mutex_lock(&LOCK_log);
  int ret = raw_get_current_log(linfo);
  mysql_mutex_unlock(&LOCK_log);
  return ret;
}


extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
{
  THD *thd=current_thd;
  DBUG_ENTER("end_thread_signal");
  if (thd && ! thd->bootstrap)
  {
    statistic_increment(killed_threads, &LOCK_status);
    MYSQL_CALLBACK(thread_scheduler, end_thread, (thd,0)); /* purecov: inspected */
  }
  DBUG_VOID_RETURN;				/* purecov: deadcode */
}


static bool update_timestamp(THD *thd, set_var *var)
{
  if (var->value)
    thd->set_time((time_t) var->save_result.ulonglong_value);
  else // SET timestamp=DEFAULT
    thd->user_time= 0;
  return false;
}


check_max_allowed_packet(sys_var *self, THD *thd,  set_var *var)
{
  longlong val;
  if (session_readonly(self, thd, var))
    return true;

  val= var->save_result.ulonglong_value;
  if (val < (longlong) global_system_variables.net_buffer_length)
  {
    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                        WARN_OPTION_BELOW_LIMIT, ER(WARN_OPTION_BELOW_LIMIT),
                        "max_allowed_packet", "net_buffer_length");
  }
  return false;
}


static void mysqld_exit(int exit_code)
{
  /*
    Important note: we wait for the signal thread to end,
    but if a kill -15 signal was sent, the signal thread did
    spawn the kill_server_thread thread, which is running concurrently.
  */
  wait_for_signal_thread_to_end();
  mysql_audit_finalize();
  clean_up_mutexes();
  clean_up_error_log_mutex();
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
  /*
    Bug#56666 needs to be fixed before calling:
    shutdown_performance_schema();
  */
#endif
  my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
  exit(exit_code); /* purecov: inspected */
}


static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff)
{
  mysql_mutex_lock(&LOCK_active_mi);
  if (active_mi)
  {
    var->type= SHOW_LONGLONG;
    var->value= buff;
    mysql_mutex_lock(&active_mi->rli.data_lock);
    *((longlong *)buff)= active_mi->received_heartbeats;
    mysql_mutex_unlock(&active_mi->rli.data_lock);
  }
  else
    var->type= SHOW_UNDEF;
  mysql_mutex_unlock(&LOCK_active_mi);
  return 0;
}


static void start_signal_handler(void)
{
  int error;
  pthread_attr_t thr_attr;
  DBUG_ENTER("start_signal_handler");

  (void) pthread_attr_init(&thr_attr);
#if !defined(HAVE_DEC_3_2_THREADS)
  pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
  (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
#if defined(__ia64__) || defined(__ia64)
  /*
    Peculiar things with ia64 platforms - it seems we only have half the
    stack size in reality, so we have to double it here
  */
  pthread_attr_setstacksize(&thr_attr,my_thread_stack_size*2);
#else
  pthread_attr_setstacksize(&thr_attr,my_thread_stack_size);
#endif
#endif

  mysql_mutex_lock(&LOCK_thread_count);
  if ((error= mysql_thread_create(key_thread_signal_hand,
                                  &signal_thread, &thr_attr, signal_hand, 0)))
  {
    sql_print_error("Can't create interrupt-thread (error %d, errno: %d)",
		    error,errno);
    exit(1);
  }
  mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
  mysql_mutex_unlock(&LOCK_thread_count);

  (void) pthread_attr_destroy(&thr_attr);
  DBUG_VOID_RETURN;
}


bool check_secure_file_priv_path()
{
  char datadir_buffer[FN_REFLEN+1]={0};
  char plugindir_buffer[FN_REFLEN+1]={0};
  char whichdir[20]= {0};
  size_t opt_plugindir_len= 0;
  size_t opt_datadir_len= 0;
  size_t opt_secure_file_priv_len= 0;
  bool warn= false;
  bool case_insensitive_fs;
#ifndef _WIN32
  MY_STAT dir_stat;
#endif

  if (!opt_secure_file_priv[0])
  {
    if (opt_bootstrap)
    {
      /*
        Do not impose --secure-file-priv restriction
        in --bootstrap mode
      */
      sql_print_information("Ignoring --secure-file-priv value as server is "
                            "running with --bootstrap.");
    }
    else
    {
      sql_print_warning("Insecure configuration for --secure-file-priv: "
                        "Current value does not restrict location of generated "
                        "files. Consider setting it to a valid, "
                        "non-empty path.");
    }
    return true;
  }

  /*
    Setting --secure-file-priv to NULL would disable
    reading/writing from/to file
  */
  if(!my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL"))
  {
    sql_print_information("--secure-file-priv is set to NULL. "
                          "Operations related to importing and exporting "
                          "data are disabled");
    return true;
  }

  /*
    Check if --secure-file-priv can access data directory
  */
  opt_secure_file_priv_len= strlen(opt_secure_file_priv);

  /*
    Adds dir seperator at the end.
    This is required in subsequent comparison
  */
  convert_dirname(datadir_buffer, mysql_unpacked_real_data_home, NullS);
  opt_datadir_len= strlen(datadir_buffer);

  case_insensitive_fs=
    (test_if_case_insensitive(datadir_buffer) == 1);

  if (!case_insensitive_fs)
  {
    if (!strncmp(datadir_buffer, opt_secure_file_priv,
          opt_datadir_len < opt_secure_file_priv_len ?
          opt_datadir_len : opt_secure_file_priv_len))
    {
      warn= true;
      strcpy(whichdir, "Data directory");
    }
  }
  else
  {
    if (!files_charset_info->coll->strnncoll(files_charset_info,
          (uchar *) datadir_buffer,
          opt_datadir_len,
          (uchar *) opt_secure_file_priv,
          opt_secure_file_priv_len,
          TRUE))
    {
      warn= true;
      strcpy(whichdir, "Data directory");
    }
  }

  /*
    Don't bother comparing --secure-file-priv with --plugin-dir
    if we already have a match against --datadir or
    --plugin-dir is not pointing to a valid directory.
  */
  if (!warn && !my_realpath(plugindir_buffer, opt_plugin_dir, 0))
  {
    convert_dirname(plugindir_buffer, plugindir_buffer, NullS);
    opt_plugindir_len= strlen(plugindir_buffer);

    if (!case_insensitive_fs)
    {
      if (!strncmp(plugindir_buffer, opt_secure_file_priv,
          opt_plugindir_len < opt_secure_file_priv_len ?
          opt_plugindir_len : opt_secure_file_priv_len))
      {
        warn= true;
        strcpy(whichdir, "Plugin directory");
      }
    }
    else
    {
      if (!files_charset_info->coll->strnncoll(files_charset_info,
          (uchar *) plugindir_buffer,
          opt_plugindir_len,
          (uchar *) opt_secure_file_priv,
          opt_secure_file_priv_len,
          TRUE))
      {
        warn= true;
        strcpy(whichdir, "Plugin directory");
      }
    }
  }

  if (warn)
    sql_print_warning("Insecure configuration for --secure-file-priv: "
                      "%s is accessible through "
                      "--secure-file-priv. Consider choosing a different "
                      "directory.", whichdir);

#ifndef _WIN32
  /*
     Check for --secure-file-priv directory's permission
  */
  if (!(my_stat(opt_secure_file_priv, &dir_stat, MYF(0))))
  {
    sql_print_error("Failed to get stat for directory pointed out "
                    "by --secure-file-priv");
    return false;
  }

  if (dir_stat.st_mode & S_IRWXO)
    sql_print_warning("Insecure configuration for --secure-file-priv: "
                      "Location is accessible to all OS users. "
                      "Consider choosing a different directory.");
#endif
  return true;
}