XkbExtensionInit(void)
{
    ExtensionEntry *extEntry;

    RT_XKBCLIENT = CreateNewResourceType(XkbClientGone, "XkbClient");
    if (!RT_XKBCLIENT)
        return;

    if (!XkbInitPrivates())
        return;

    if ((extEntry = AddExtension(XkbName, XkbNumberEvents, XkbNumberErrors,
                                 ProcXkbDispatch, SProcXkbDispatch,
                                 NULL, StandardMinorOpcode))) {
        XkbReqCode = (unsigned char) extEntry->base;
        XkbEventBase = (unsigned char) extEntry->eventBase;
        XkbErrorBase = (unsigned char) extEntry->errorBase;
        XkbKeyboardErrorCode = XkbErrorBase + XkbKeyboard;
    }
    return;
}


XkbComputeGetIndicatorMapReplySize(XkbIndicatorPtr indicators,
                                   xkbGetIndicatorMapReply * rep)
{
    register int i, bit;
    int nIndicators;

    rep->realIndicators = indicators->phys_indicators;
    for (i = nIndicators = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
        if (rep->which & bit)
            nIndicators++;
    }
    rep->length = (nIndicators * SIZEOF(xkbIndicatorMapWireDesc)) / 4;
    rep->nIndicators = nIndicators;
    return Success;
}


SetVirtualModMap(XkbSrvInfoPtr xkbi,
                 xkbSetMapReq * req,
                 xkbVModMapWireDesc * wire, XkbChangesPtr changes)
{
    register unsigned i, first, last;
    XkbServerMapPtr srv = xkbi->desc->server;

    first = req->firstVModMapKey;
    last = req->firstVModMapKey + req->nVModMapKeys - 1;
    memset(&srv->vmodmap[first], 0, req->nVModMapKeys * sizeof(unsigned short));
    for (i = 0; i < req->totalVModMapKeys; i++, wire++) {
        srv->vmodmap[wire->key] = wire->vmods;
    }
    if (first > 0) {
        if (changes->map.changed & XkbVirtualModMapMask) {
            int oldLast;

            oldLast = changes->map.first_vmodmap_key +
                changes->map.num_vmodmap_keys - 1;
            if (changes->map.first_vmodmap_key < first)
                first = changes->map.first_vmodmap_key;
            if (oldLast > last)
                last = oldLast;
        }
        changes->map.first_vmodmap_key = first;
        changes->map.num_vmodmap_keys = (last - first) + 1;
    }
    return (char *) wire;
}


XkbComputeGetMapReplySize(XkbDescPtr xkb, xkbGetMapReply * rep)
{
    int len;

    rep->minKeyCode = xkb->min_key_code;
    rep->maxKeyCode = xkb->max_key_code;
    len = XkbSizeKeyTypes(xkb, rep);
    len += XkbSizeKeySyms(xkb, rep);
    len += XkbSizeKeyActions(xkb, rep);
    len += XkbSizeKeyBehaviors(xkb, rep);
    len += XkbSizeVirtualMods(xkb, rep);
    len += XkbSizeExplicit(xkb, rep);
    len += XkbSizeModifierMap(xkb, rep);
    len += XkbSizeVirtualModMap(xkb, rep);
    rep->length += (len / 4);
    return Success;
}


_CheckSetGeom(XkbGeometryPtr geom, xkbSetGeometryReq * req, ClientPtr client)
{
    register int i;
    Status status;
    char *wire;

    wire = (char *) &req[1];
    status = _GetCountedString(&wire, client, &geom->label_font);
    if (status != Success)
        return status;

    for (i = 0; i < req->nProperties; i++) {
        char *name, *val;

        status = _GetCountedString(&wire, client, &name);
        if (status != Success)
            return status;
        status = _GetCountedString(&wire, client, &val);
        if (status != Success) {
            free(name);
            return status;
        }
        if (XkbAddGeomProperty(geom, name, val) == NULL) {
            free(name);
            free(val);
            return BadAlloc;
        }
        free(name);
        free(val);
    }

    if (req->nColors < 2) {
        client->errorValue = _XkbErrCode3(0x01, 2, req->nColors);
        return BadValue;
    }
    if (req->baseColorNdx > req->nColors) {
        client->errorValue =
            _XkbErrCode3(0x03, req->nColors, req->baseColorNdx);
        return BadMatch;
    }
    if (req->labelColorNdx > req->nColors) {
        client->errorValue =
            _XkbErrCode3(0x03, req->nColors, req->labelColorNdx);
        return BadMatch;
    }
    if (req->labelColorNdx == req->baseColorNdx) {
        client->errorValue = _XkbErrCode3(0x04, req->baseColorNdx,
                                          req->labelColorNdx);
        return BadMatch;
    }

    for (i = 0; i < req->nColors; i++) {
        char *name;

        status = _GetCountedString(&wire, client, &name);
        if (status != Success)
            return status;
        if (!XkbAddGeomColor(geom, name, geom->num_colors)) {
            free(name);
            return BadAlloc;
        }
        free(name);
    }
    if (req->nColors != geom->num_colors) {
        client->errorValue = _XkbErrCode3(0x05, req->nColors, geom->num_colors);
        return BadMatch;
    }
    geom->label_color = &geom->colors[req->labelColorNdx];
    geom->base_color = &geom->colors[req->baseColorNdx];

    if ((status = _CheckSetShapes(geom, req, &wire, client)) != Success)
        return status;

    if ((status = _CheckSetSections(geom, req, &wire, client)) != Success)
        return status;

    for (i = 0; i < req->nDoodads; i++) {
        status = _CheckSetDoodad(&wire, geom, NULL, client);
        if (status != Success)
            return status;
    }

    for (i = 0; i < req->nKeyAliases; i++) {
        if (XkbAddGeomKeyAlias(geom, &wire[XkbKeyNameLength], wire) == NULL)
            return BadAlloc;
        wire += 2 * XkbKeyNameLength;
    }
    return Success;
}


ProcXkbDispatch(ClientPtr client)
{
    REQUEST(xReq);
    switch (stuff->data) {
    case X_kbUseExtension:
        return ProcXkbUseExtension(client);
    case X_kbSelectEvents:
        return ProcXkbSelectEvents(client);
    case X_kbBell:
        return ProcXkbBell(client);
    case X_kbGetState:
        return ProcXkbGetState(client);
    case X_kbLatchLockState:
        return ProcXkbLatchLockState(client);
    case X_kbGetControls:
        return ProcXkbGetControls(client);
    case X_kbSetControls:
        return ProcXkbSetControls(client);
    case X_kbGetMap:
        return ProcXkbGetMap(client);
    case X_kbSetMap:
        return ProcXkbSetMap(client);
    case X_kbGetCompatMap:
        return ProcXkbGetCompatMap(client);
    case X_kbSetCompatMap:
        return ProcXkbSetCompatMap(client);
    case X_kbGetIndicatorState:
        return ProcXkbGetIndicatorState(client);
    case X_kbGetIndicatorMap:
        return ProcXkbGetIndicatorMap(client);
    case X_kbSetIndicatorMap:
        return ProcXkbSetIndicatorMap(client);
    case X_kbGetNamedIndicator:
        return ProcXkbGetNamedIndicator(client);
    case X_kbSetNamedIndicator:
        return ProcXkbSetNamedIndicator(client);
    case X_kbGetNames:
        return ProcXkbGetNames(client);
    case X_kbSetNames:
        return ProcXkbSetNames(client);
    case X_kbGetGeometry:
        return ProcXkbGetGeometry(client);
    case X_kbSetGeometry:
        return ProcXkbSetGeometry(client);
    case X_kbPerClientFlags:
        return ProcXkbPerClientFlags(client);
    case X_kbListComponents:
        return ProcXkbListComponents(client);
    case X_kbGetKbdByName:
        return ProcXkbGetKbdByName(client);
    case X_kbGetDeviceInfo:
        return ProcXkbGetDeviceInfo(client);
    case X_kbSetDeviceInfo:
        return ProcXkbSetDeviceInfo(client);
    case X_kbSetDebuggingFlags:
        return ProcXkbSetDebuggingFlags(client);
    default:
        return BadRequest;
    }
}


_XimDecodeInnerIMATTRIBUTE(
    Xim			 im,
    XIMArg		*arg)
{
    XIMResourceList	 res;
    XimDefIMValues	 im_values;

    if (!(res = _XimGetResourceListRec(im->private.proto.im_inner_resources,
			im->private.proto.im_num_inner_resources, arg->name)))
	return False;

    _XimGetCurrentIMValues(im, &im_values);
    return _XimDecodeLocalIMAttr(res, (XPointer)&im_values, arg->value);
}


_XimDecodeInnerICATTRIBUTE(
    Xic			 ic,
    XIMArg		*arg,
    unsigned long	 mode)
{
    XIMResourceList	 res;
    XimDefICValues	 ic_values;

    if (!(res = _XimGetResourceListRec(ic->private.proto.ic_inner_resources,
			ic->private.proto.ic_num_inner_resources, arg->name)))
	return False;

    _XimGetCurrentICValues(ic, &ic_values);
    if (!_XimDecodeLocalICAttr(res, (XPointer)&ic_values, arg->value, mode))
	return False;
    _XimSetCurrentICValues(ic, &ic_values);
    return True;
}


_XimMakeIMAttrIDList(
    Xim			 im,
    XIMResourceList	 res_list,
    unsigned int	 res_num,
    XIMArg		*arg,
    CARD16		*buf,
    INT16		*len,
    unsigned long	 mode)
{
    register XIMArg	*p;
    XIMResourceList	 res;
    int			 check;

    *len = 0;
    if (!arg)
	return (char *)NULL;

    for (p = arg; p->name; p++) {
	if (!(res = _XimGetResourceListRec(res_list, res_num, p->name))) {
	    if (_XimCheckInnerIMAttributes(im, p, mode))
		continue;
	    return p->name;
	}

	check = _XimCheckIMMode(res, mode);
	if (check == XIM_CHECK_INVALID)
	    continue;
	else if (check == XIM_CHECK_ERROR)
	    return p->name;

	*buf = res->id;
	*len += sizeof(CARD16);
	 buf++;
    }
    return (char *)NULL;
}


_XimEncodeSavedICATTRIBUTE(
    Xic			 ic,
    XIMResourceList	 res_list,
    unsigned int	 res_num,
    int			*idx,
    char		*buf,
    int			 size,
    int			*ret_len,
    XPointer		 top,
    unsigned long	 mode)
{
    int			 i;
    int			 num = ic->private.proto.num_saved_icvalues;
    XrmQuark		*quark_list = ic->private.proto.saved_icvalues;
    XIMResourceList	 res;
    XPointer		 value;
    CARD16		*buf_s;
    int			 len;
    int			 min_len = sizeof(CARD16) /* sizeof attribute ID */
				 + sizeof(INT16); /* sizeof value length */
    XrmQuark		 pre_quark;
    XrmQuark		 sts_quark;
    XrmQuark		 separator;

    if (!ic->private.proto.saved_icvalues) {
	*idx = -1;
	*ret_len = 0;
	return True;
    }

    pre_quark = XrmStringToQuark(XNPreeditAttributes);
    sts_quark = XrmStringToQuark(XNStatusAttributes);
    separator = XrmStringToQuark(XNSeparatorofNestedList);

    *ret_len = 0;
    for (i = *idx; i < num; i++) {
	if (quark_list[i] == separator) {
	    *idx = i;
	    return True;
	}

	if (!(res = _XimGetResourceListRecByQuark(res_list,
						res_num, quark_list[i])))
	    continue;

	if (!_XimDecodeLocalICAttr(res, top,(XPointer)&value, mode))
	    return False;

	if (mode & XIM_PREEDIT_ATTR) {
	    if (!(_XimEncodeSavedPreeditValue(ic, res, value))) {
		return False;
	    }
	} else if (mode & XIM_STATUS_ATTR) {
	    if (!(_XimEncodeSavedStatusValue(ic, res, value))) {
		return False;
	    }
	}

	buf_s = (CARD16 *)buf;
	if (res->resource_size == XimType_NEST) {
	    XimDefICValues	*ic_attr = (XimDefICValues *)top;

	    i++;
	    if (res->xrm_name == pre_quark) {
		if (!_XimEncodeSavedICATTRIBUTE(ic, res_list, res_num,
				 &i, (char *)&buf_s[2], (size - min_len),
				 &len, (XPointer)&ic_attr->preedit_attr,
				(mode | XIM_PREEDIT_ATTR))) {
		    return False;
		}

	    } else if (res->xrm_name == sts_quark) {
		if (!_XimEncodeSavedICATTRIBUTE(ic, res_list, res_num,
				&i, (char *)&buf_s[2], (size - min_len),
				&len, (XPointer)&ic_attr->status_attr,
				(mode | XIM_STATUS_ATTR))) {
		    return False;
		}
	    }
	} else {
	    if (!(_XimValueToAttribute(res, (XPointer)&buf_s[2],
			 	(size - min_len), value,
				&len, mode, (XPointer)ic))) {
		return False;
	    }
	}

	if (len == 0) {
	    continue;
	} else if (len < 0) {
	    if (quark_list[i] == separator)
		i++;
	    *idx = i;
	    return True;
	}

	buf_s[0] = res->id;			/* attribute ID */
	buf_s[1] = len;				/* value length */
	XIM_SET_PAD(&buf_s[2], len);		/* pad */
	len += min_len;

	buf += len;
	*ret_len += len;
	size -= len;
    }
    *idx = -1;
    return True;
}


_XimDecodeICATTRIBUTE(
    Xic			 ic,
    XIMResourceList	 res_list,
    unsigned int	 res_num,
    CARD16		*data,
    INT16		 data_len,
    XIMArg		*arg,
    BITMASK32		 mode)
{
    register XIMArg	*p;
    XIMResourceList	 res;
    int			 check;
    INT16		 len;
    CARD16		*buf;
    INT16		 total;
    char		*name;
    INT16		 min_len = sizeof(CARD16)	/* sizeof attributeID */
			 	 + sizeof(INT16);	/* sizeof length */
    XrmQuark		 pre_quark;
    XrmQuark		 sts_quark;

    if (!arg)
	return (char *)NULL;

    pre_quark = XrmStringToQuark(XNPreeditAttributes);
    sts_quark = XrmStringToQuark(XNStatusAttributes);

    for (p = arg; p->name; p++) {
	if (!(res = _XimGetResourceListRec(res_list, res_num, p->name))) {
	    if (_XimDecodeInnerICATTRIBUTE(ic, p, mode))
		continue;
	    return p->name;
	}

	check = _XimCheckICMode(res, mode);
	if (check == XIM_CHECK_INVALID)
	    continue;
	else if (check == XIM_CHECK_ERROR)
	    return p->name;

	total = data_len;
	buf = data;
	while (total >= min_len) {
	    if (res->id == buf[0])
		break;

	    len = buf[1];
	    len += XIM_PAD(len) + min_len;
	    buf = (CARD16 *)((char *)buf + len);
	    total -= len;
	}
	if (total < min_len)
	    return p->name;

	if (res->resource_size == XimType_NEST) {
	    if (res->xrm_name == pre_quark) {
	        if ((name = _XimDecodeICATTRIBUTE(ic, res_list, res_num,
			&buf[2], buf[1], (XIMArg *)p->value,
			(mode | XIM_PREEDIT_ATTR))))
		    return name;
	    } else if (res->xrm_name == sts_quark) {
	        if ((name = _XimDecodeICATTRIBUTE(ic, res_list, res_num,
			&buf[2], buf[1], (XIMArg *)p->value,
			(mode | XIM_STATUS_ATTR))))
		    return name;
	    }
	} else {
	    if (!(_XimAttributeToValue(ic, res, &buf[2], buf[1],
							p->value, mode)))
		return p->name;
	}
    }
    return (char *)NULL;
}


_XimGetEncoding(
    Xim		 im,
    CARD16	*buf,
    char	*name,
    int		 name_len,
    char	*detail,
    int		 detail_len)
{
    XLCd	 lcd = im->core.lcd;
    CARD16	 category = buf[0];
    CARD16	 idx = buf[1];
    int		 len;
    XlcConv	 ctom_conv = NULL;
    XlcConv	 ctow_conv = NULL;
    XlcConv	 ctoutf8_conv = NULL;
    XlcConv	 conv;
    XimProtoPrivateRec *private = &im->private.proto;

    if (idx == (CARD16)XIM_Default_Encoding_IDX) { /* XXX */
	if (!(ctom_conv = _XlcOpenConverter(lcd,
				 XlcNCompoundText, lcd, XlcNMultiByte)))
	    return False;
	if (!(ctow_conv = _XlcOpenConverter(lcd,
				 XlcNCompoundText, lcd, XlcNWideChar)))
	    return False;
	if (!(ctoutf8_conv = _XlcOpenConverter(lcd,
				 XlcNCompoundText, lcd, XlcNUtf8String)))
	    return False;
    }

    if (category == XIM_Encoding_NameCategory) {
	while (name_len > 0) {
	    len = (int)name[0];
	    if (!strncmp(&name[1], "COMPOUND_TEXT", len)) {
		if (!(ctom_conv = _XlcOpenConverter(lcd,
				 XlcNCompoundText, lcd, XlcNMultiByte)))
		    return False;
		if (!(ctow_conv = _XlcOpenConverter(lcd,
				 XlcNCompoundText, lcd, XlcNWideChar)))
		    return False;
		if (!(ctoutf8_conv = _XlcOpenConverter(lcd,
				 XlcNCompoundText, lcd, XlcNUtf8String)))
		    return False;
		break;
	    } else {
		/*
		 * Not yet
		 */
	    }
	    len += sizeof(BYTE);
	    name_len -= len;
	    name += len;
	}
    } else if (category == XIM_Encoding_DetailCategory) {
	/*
	 * Not yet
	 */
    } else {
	return False;
    }

    private->ctom_conv = ctom_conv;
    private->ctow_conv = ctow_conv;
    private->ctoutf8_conv = ctoutf8_conv;

    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNMultiByte)))
	return False;
    private->cstomb_conv = conv;

    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNWideChar)))
	return False;
    private->cstowc_conv = conv;

    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNUtf8String)))
	return False;
    private->cstoutf8_conv = conv;

    if (!(conv = _XlcOpenConverter(lcd,	XlcNUcsChar, lcd, XlcNChar)))
	return False;
    private->ucstoc_conv = conv;

    if (!(conv = _XlcOpenConverter(lcd,	XlcNUcsChar, lcd, XlcNUtf8String)))
	return False;
    private->ucstoutf8_conv = conv;

    return True;
}


_XimDelayModeSetAttr(
    Xim			 im)
{
    XimDefIMValues	 im_values;

    if(!_XimSetIMResourceList(&im->core.im_resources,
						&im->core.im_num_resources)) {
	return False;
    }
    if(!_XimSetICResourceList(&im->core.ic_resources,
						&im->core.ic_num_resources)) {
	return False;
    }

    _XimSetIMMode(im->core.im_resources, im->core.im_num_resources);

    _XimGetCurrentIMValues(im, &im_values);
    if(!_XimSetLocalIMDefaults(im, (XPointer)&im_values,
			im->core.im_resources, im->core.im_num_resources)) {
	return False;
    }
    _XimSetCurrentIMValues(im, &im_values);
    if (im->private.proto.default_styles) {
        if (im->core.styles)
	    Xfree(im->core.styles);
        im->core.styles = im->private.proto.default_styles;
    }

    return True;
}


_XimDelayModeSetIMValues(
    Xim			 im,
    XIMArg		*arg)
{
    XimDefIMValues	 im_values;
    char		*name;
    XIMArg		*values;

    _XimGetCurrentIMValues(im, &im_values);
    name = _XimSetIMValueData(im, (XPointer)&im_values, values,
		im->core.im_resources, im->core.im_num_resources);
    _XimSetCurrentIMValues(im, &im_values);

    return name;
}


_XimDelayModeSetICValues(ic, arg)
    Xic			 ic;
    XIMArg		*arg;
{
    XimDefICValues	 ic_values;
    char		*name;

    _XimGetCurrentICValues(ic, &ic_values);
    name = _XimSetICValueData(ic, (XPointer)&ic_values,
			ic->private.proto.ic_resources,
			ic->private.proto.ic_num_resources,
			arg, XIM_SETICVALUES, False);
    _XimSetCurrentICValues(ic, &ic_values);
    return name;
}


_XimSetAuthReplyData(
    Xim		 im,
    XPointer	 buf,
    INT16	*len)
{
    /*
     * Not yet
     */
    *len = 0;
    return True;
}


_XimProtoOpenIM(
    Xim		 im)
{
    _XimInitialResourceInfo();

    im->methods = &im_methods;

#ifdef XIM_CONNECTABLE
    _XimSetProtoResource(im);
#endif /* XIM_CONNECTABLE */

    if (_XimPreConnect(im)) {
	if (_XimConnection(im) && _XimOpen(im) && _XimEncodingNegotiation(im)) {
	    _XimRegisterServerFilter(im);
	    return True;
	}
	_XimShutdown(im);
#ifdef XIM_CONNECTABLE
    } else if (IS_DELAYBINDABLE(im)) {
	if (_XimDelayModeSetAttr(im))
	    return True;
#endif /* XIM_CONNECTABLE */
    }
    _XimProtoIMFree(im);
    return False;
}


_XimPreConnect(
    Xim		    im)
{
    Display	   *display = im->core.display;
    Atom	    imserver;
    Atom	    actual_type;
    int		    actual_format;
    unsigned long   nitems;
    unsigned long   bytes_after;
    unsigned char  *prop_return;
    Atom	   *atoms;
    Window	    im_window = 0;
    register int    i;

    if((imserver = XInternAtom(display, XIM_SERVERS, True)) == (Atom)None)
	return False;

    if(XGetWindowProperty(display, RootWindow(display, 0),
			imserver, 0L, 1000000L, False, XA_ATOM, &actual_type,
			&actual_format, &nitems, &bytes_after,
			&prop_return) != Success)
	return False;

    if( (actual_type != XA_ATOM) || (actual_format != 32) ) {
	if( nitems )
	    XFree((XPointer)prop_return);
	return False;
    }

    atoms = (Atom *)prop_return;
    for(i = 0; i < nitems; i++) {
	if((im_window = XGetSelectionOwner(display, atoms[i])) == (Window)None)
	    continue;

	if(_XimPreConnectionIM(im, atoms[i]))
	    break;
    }

    XFree((XPointer)prop_return);
    if(i >= nitems)
	return False;

    im->private.proto.im_window = im_window;
    return True;
}


_XimCreateICCheck(
    Xim          im,
    INT16        len,
    XPointer	 data,
    XPointer     arg)
{
    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
    CARD8	 major_opcode = *((CARD8 *)data);
    CARD8	 minor_opcode = *((CARD8 *)data + 1);
    XIMID	 imid = buf_s[0];

    if ((major_opcode == XIM_CREATE_IC_REPLY)
     && (minor_opcode == 0)
     && (imid == im->private.proto.imid))
	return True;
    if ((major_opcode == XIM_ERROR)
     && (minor_opcode == 0)
     && (buf_s[2] & XIM_IMID_VALID)
     && (imid == im->private.proto.imid))
	return True;
    return False;
}


_XimProtoUtf8Reset(
    XIC		 xic)
{
    return _XimProtoReset(xic, _XimCommitedUtf8String);
}


void sftp_client_message_free(sftp_client_message msg) {
  if (msg == NULL) {
    return;
  }

  SAFE_FREE(msg->filename);
  SAFE_FREE(msg->submessage);
  SSH_STRING_FREE(msg->data);
  SSH_STRING_FREE(msg->handle);
  sftp_attributes_free(msg->attr);
  SSH_BUFFER_FREE(msg->complete_message);
  SAFE_FREE(msg->str_data);
  ZERO_STRUCTP(msg);
  SAFE_FREE(msg);
}


void sftp_handle_remove(sftp_session sftp, void *handle) {
  int i;

  for (i = 0; i < SFTP_HANDLES; i++) {
    if (sftp->handles[i] == handle) {
      sftp->handles[i] = NULL;
      break;
    }
  }
}


ssh_string sftp_handle_alloc(sftp_session sftp, void *info) {
  ssh_string ret;
  uint32_t val;
  uint32_t i;

  if (sftp->handles == NULL) {
    sftp->handles = calloc(SFTP_HANDLES, sizeof(void *));
    if (sftp->handles == NULL) {
      return NULL;
    }
  }

  for (i = 0; i < SFTP_HANDLES; i++) {
    if (sftp->handles[i] == NULL) {
      break;
    }
  }

  if (i == SFTP_HANDLES) {
    return NULL; /* no handle available */
  }

  val = i;
  ret = ssh_string_new(4);
  if (ret == NULL) {
    return NULL;
  }

  memcpy(ssh_string_data(ret), &val, sizeof(uint32_t));
  sftp->handles[i] = info;

  return ret;
}


int sftp_reply_status(sftp_client_message msg, uint32_t status,
    const char *message) {
  ssh_buffer out;
  ssh_string s;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  s = ssh_string_from_char(message ? message : "");
  if (s == NULL) {
    SSH_BUFFER_FREE(out);
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_u32(out, htonl(status)) < 0 ||
      ssh_buffer_add_ssh_string(out, s) < 0 ||
      ssh_buffer_add_u32(out, 0) < 0 || /* language string */
      sftp_packet_write(msg->sftp, SSH_FXP_STATUS, out) < 0) {
    SSH_BUFFER_FREE(out);
    SSH_STRING_FREE(s);
    return -1;
  }

  SSH_BUFFER_FREE(out);
  SSH_STRING_FREE(s);

  return 0;
}


int sftp_reply_name(sftp_client_message msg, const char *name,
    sftp_attributes attr) {
  ssh_buffer out;
  ssh_string file;

  out = ssh_buffer_new();
  if (out == NULL) {
    return -1;
  }

  file = ssh_string_from_char(name);
  if (file == NULL) {
    SSH_BUFFER_FREE(out);
    return -1;
  }

  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
      ssh_buffer_add_u32(out, htonl(1)) < 0 ||
      ssh_buffer_add_ssh_string(out, file) < 0 ||
      ssh_buffer_add_ssh_string(out, file) < 0 || /* The protocol is broken here between 3 & 4 */
      buffer_add_attributes(out, attr) < 0 ||
      sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
    SSH_BUFFER_FREE(out);
    SSH_STRING_FREE(file);
    return -1;
  }
  SSH_BUFFER_FREE(out);
  SSH_STRING_FREE(file);

  return 0;
}


void *ssh_buffer_get(struct ssh_buffer_struct *buffer){
    return buffer->data + buffer->pos;
}


int ssh_buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
{
    int rc;

    rc = ssh_buffer_add_data(buffer, &data, sizeof(data));
    if (rc < 0) {
        return -1;
    }

    return 0;
}


static void buffer_verify(ssh_buffer buf)
{
    bool do_abort = false;

    if (buf->data == NULL) {
        return;
    }

    if (buf->used > buf->allocated) {
        fprintf(stderr,
                "BUFFER ERROR: allocated %zu, used %zu\n",
                buf->allocated,
                buf->used);
        do_abort = true;
    }
    if (buf->pos > buf->used) {
        fprintf(stderr,
                "BUFFER ERROR: position %zu, used %zu\n",
                buf->pos,
                buf->used);
        do_abort = true;
    }
    if (buf->pos > buf->allocated) {
        fprintf(stderr,
                "BUFFER ERROR: position %zu, allocated %zu\n",
                buf->pos,
                buf->allocated);
        do_abort = true;
    }
    if (do_abort) {
        abort();
    }
}


which_module(const char *name)
{
    struct module  *mp;

    for (mp = module_head; mp; mp = mp->next)
        if (!label_compare(mp->name, name))
            return (mp->modid);

    DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name));
    return (-1);
}


netsnmp_get_mib_directory(void)
{
    char *dir;

    DEBUGTRACE;
    dir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS);
    if (dir == NULL) {
        DEBUGMSGTL(("get_mib_directory", "no mib directories set\n"));

        /** Check if the environment variable is set */
        dir = netsnmp_getenv("MIBDIRS");
        if (dir == NULL) {
            DEBUGMSGTL(("get_mib_directory", "no mib directories set by environment\n"));
            /** Not set use hard coded path */
            if (confmibdir == NULL) {
                DEBUGMSGTL(("get_mib_directory", "no mib directories set by config\n"));
                netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS);
            }
            else if ((*confmibdir == '+') || (*confmibdir == '-')) {
                DEBUGMSGTL(("get_mib_directory", "mib directories set by config (but added)\n"));
                netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS);
                netsnmp_set_mib_directory(confmibdir);
            }
            else {
                DEBUGMSGTL(("get_mib_directory", "mib directories set by config\n"));
                netsnmp_set_mib_directory(confmibdir);
            }
        } else if ((*dir == '+') || (*dir == '-')) {
            DEBUGMSGTL(("get_mib_directory", "mib directories set by environment (but added)\n"));
            netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS);
            netsnmp_set_mib_directory(dir);
        } else {
            DEBUGMSGTL(("get_mib_directory", "mib directories set by environment\n"));
            netsnmp_set_mib_directory(dir);
        }
        dir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS);
    }
    DEBUGMSGTL(("get_mib_directory", "mib directories set '%s'\n", dir));
    return(dir);
}


uptimeString(u_long timeticks, char *buf, size_t buflen)
{
    int             centisecs, seconds, minutes, hours, days;

    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS)) {
        snprintf(buf, buflen, "%lu", timeticks);
        return buf;
    }

    centisecs = timeticks % 100;
    timeticks /= 100;
    days = timeticks / (60 * 60 * 24);
    timeticks %= (60 * 60 * 24);

    hours = timeticks / (60 * 60);
    timeticks %= (60 * 60);

    minutes = timeticks / 60;
    seconds = timeticks % 60;

    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT))
        snprintf(buf, buflen, "%d:%d:%02d:%02d.%02d",
                days, hours, minutes, seconds, centisecs);
    else {
        if (days == 0) {
            snprintf(buf, buflen, "%d:%02d:%02d.%02d",
                    hours, minutes, seconds, centisecs);
        } else if (days == 1) {
            snprintf(buf, buflen, "%d day, %d:%02d:%02d.%02d",
                    days, hours, minutes, seconds, centisecs);
        } else {
            snprintf(buf, buflen, "%d days, %d:%02d:%02d.%02d",
                    days, hours, minutes, seconds, centisecs);
        }
    }
    return buf;
}


init_tree_roots(void)
{
    struct tree    *tp, *lasttp;
    int             base_modid;
    int             hash;

    base_modid = which_module("SNMPv2-SMI");
    if (base_modid == -1)
        base_modid = which_module("RFC1155-SMI");
    if (base_modid == -1)
        base_modid = which_module("RFC1213-MIB");

    /*
     * build root node
     */
    tp = (struct tree *) calloc(1, sizeof(struct tree));
    if (tp == NULL)
        return;
    tp->label = strdup("joint-iso-ccitt");
    tp->modid = base_modid;
    tp->number_modules = 1;
    tp->module_list = &(tp->modid);
    tp->subid = 2;
    tp->tc_index = -1;
    set_function(tp);           /* from mib.c */
    hash = NBUCKET(name_hash(tp->label));
    tp->next = tbuckets[hash];
    tbuckets[hash] = tp;
    lasttp = tp;
    root_imports[0].label = strdup(tp->label);
    root_imports[0].modid = base_modid;

    /*
     * build root node
     */
    tp = (struct tree *) calloc(1, sizeof(struct tree));
    if (tp == NULL)
        return;
    tp->next_peer = lasttp;
    tp->label = strdup("ccitt");
    tp->modid = base_modid;
    tp->number_modules = 1;
    tp->module_list = &(tp->modid);
    tp->subid = 0;
    tp->tc_index = -1;
    set_function(tp);           /* from mib.c */
    hash = NBUCKET(name_hash(tp->label));
    tp->next = tbuckets[hash];
    tbuckets[hash] = tp;
    lasttp = tp;
    root_imports[1].label = strdup(tp->label);
    root_imports[1].modid = base_modid;

    /*
     * build root node
     */
    tp = (struct tree *) calloc(1, sizeof(struct tree));
    if (tp == NULL)
        return;
    tp->next_peer = lasttp;
    tp->label = strdup("iso");
    tp->modid = base_modid;
    tp->number_modules = 1;
    tp->module_list = &(tp->modid);
    tp->subid = 1;
    tp->tc_index = -1;
    set_function(tp);           /* from mib.c */
    hash = NBUCKET(name_hash(tp->label));
    tp->next = tbuckets[hash];
    tbuckets[hash] = tp;
    lasttp = tp;
    root_imports[2].label = strdup(tp->label);
    root_imports[2].modid = base_modid;

    tree_head = tp;
}


init_mib(void)
{
    netsnmp_init_mib();
}


get_tc_descriptor(int tc_index)
{
    if (tc_index < 0 || tc_index >= MAXTC)
        return NULL;
    return (tclist[tc_index].descriptor);
}


handle_mibs_conf(const char *token, char *line)
{
    char           *ctmp;

    if (confmibs) {
        if ((*line == '+') || (*line == '-')) {
            ctmp = (char *) malloc(strlen(confmibs) + strlen(line) + 2);
            if (!ctmp) {
                DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
                return;
            }
            if(*line++ == '+')
                sprintf(ctmp, "%s%c%s", confmibs, ENV_SEPARATOR_CHAR, line);
            else
                sprintf(ctmp, "%s%c%s", line, ENV_SEPARATOR_CHAR, confmibdir);
        } else {
            ctmp = strdup(line);
            if (!ctmp) {
                DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
                return;
            }
        }
        SNMP_FREE(confmibs);
    } else {
        ctmp = strdup(line);
        if (!ctmp) {
            DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
            return;
        }
    }
    confmibs = ctmp;
    DEBUGMSGTL(("read_config:initmib", "using mibs: %s\n", confmibs));
}


_sprint_hexstring_line(u_char ** buf, size_t * buf_len, size_t * out_len,
                       int allow_realloc, const u_char * cp, size_t line_len)
{
    const u_char   *tp;
    const u_char   *cp2 = cp;
    size_t          lenleft = line_len;

    /*
     * Make sure there's enough room for the hex output....
     */
    while ((*out_len + line_len*3+1) >= *buf_len) {
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
            return 0;
        }
    }

    /*
     * .... and display the hex values themselves....
     */
    for (; lenleft >= 8; lenleft-=8) {
        sprintf((char *) (*buf + *out_len),
                "%02X %02X %02X %02X %02X %02X %02X %02X ", cp[0], cp[1],
                cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
        *out_len += strlen((char *) (*buf + *out_len));
        cp       += 8;
    }
    for (; lenleft > 0; lenleft--) {
        sprintf((char *) (*buf + *out_len), "%02X ", *cp++);
        *out_len += strlen((char *) (*buf + *out_len));
    }

    /*
     * .... plus (optionally) do the same for the ASCII equivalent.
     */
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT)) {
        while ((*out_len + line_len+5) >= *buf_len) {
            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
                return 0;
            }
        }
        sprintf((char *) (*buf + *out_len), "  [");
        *out_len += strlen((char *) (*buf + *out_len));
        for (tp = cp2; tp < cp; tp++) {
            sprint_char((char *) (*buf + *out_len), *tp);
            (*out_len)++;
        }
        sprintf((char *) (*buf + *out_len), "]");
        *out_len += strlen((char *) (*buf + *out_len));
    }
    return 1;
}


print_subtree(FILE * f, struct tree *tree, int count)
{
    struct tree    *tp;
    int             i;
    char            modbuf[256];

    for (i = 0; i < count; i++)
        fprintf(f, "  ");
    fprintf(f, "Children of %s(%ld):\n", tree->label, tree->subid);
    count++;
    for (tp = tree->child_list; tp; tp = tp->next_peer) {
        for (i = 0; i < count; i++)
            fprintf(f, "  ");
        fprintf(f, "%s:%s(%ld) type=%d",
                module_name(tp->module_list[0], modbuf),
                tp->label, tp->subid, tp->type);
        if (tp->tc_index != -1)
            fprintf(f, " tc=%d", tp->tc_index);
        if (tp->hint)
            fprintf(f, " hint=%s", tp->hint);
        if (tp->units)
            fprintf(f, " units=%s", tp->units);
        if (tp->number_modules > 1) {
            fprintf(f, " modules:");
            for (i = 1; i < tp->number_modules; i++)
                fprintf(f, " %s", module_name(tp->module_list[i], modbuf));
        }
        fprintf(f, "\n");
    }
    for (tp = tree->child_list; tp; tp = tp->next_peer) {
        if (tp->child_list)
            print_subtree(f, tp, count);
    }
}


snmp_in_toggle_options(char *options)
{
    return snmp_in_options( options, 0, NULL );
}


static int scan_directory(char ***result, const char *dirname)
{
    DIR            *dir, *dir2;
    struct dirent  *file;
    char          **filenames = NULL;
    int             fname_len, i, filename_count = 0, array_size = 0;
    char           *tmpstr;

    *result = NULL;

    dir = opendir(dirname);
    if (!dir)
        return -1;

    while ((file = readdir(dir))) {
        /*
         * Only parse file names that don't begin with a '.'
         * Also skip files ending in '~', or starting/ending
         * with '#' which are typically editor backup files.
         */
        fname_len = strlen(file->d_name);
        if (fname_len > 0 && file->d_name[0] != '.'
            && file->d_name[0] != '#'
            && file->d_name[fname_len-1] != '#'
            && file->d_name[fname_len-1] != '~') {
            if (asprintf(&tmpstr, "%s/%s", dirname, file->d_name) < 0)
                continue;
            dir2 = opendir(tmpstr);
            if (dir2) {
                /* file is a directory, don't read it */
                closedir(dir2);
            } else {
                if (filename_count >= array_size) {
                    char **new_filenames;

                    array_size = (array_size + 16) * 2;
                    new_filenames = realloc(filenames,
                                        array_size * sizeof(filenames[0]));
                    if (!new_filenames) {
                        free(tmpstr);
                        for (i = 0; i < filename_count; i++)
                            free(filenames[i]);
                        free(filenames);
                        closedir(dir);
                        return -1;
                    }
                    filenames = new_filenames;
                }
                filenames[filename_count++] = tmpstr;
                tmpstr = NULL;
            }
            free(tmpstr);
        }
    }
    closedir(dir);

    if (filenames)
        qsort(filenames, filename_count, sizeof(filenames[0]), elemcmp);
    *result = filenames;

    return filename_count;
}


_get_realloc_symbol_octet_string(size_t numids, const oid * objid,
				 u_char ** buf, size_t * buf_len,
				 size_t * out_len, int allow_realloc,
				 int *buf_overflow, struct tree* tp)
{
  netsnmp_variable_list	var = { 0 };
  u_char		buffer[1024];
  size_t		i;

  for (i = 0; i < numids; i++)
    buffer[i] = (u_char) objid[i];
  var.type = ASN_OCTET_STR;
  var.val.string = buffer;
  var.val_len = numids;
  if (!*buf_overflow) {
    if (!sprint_realloc_octet_string(buf, buf_len, out_len,
				     allow_realloc, &var,
				     NULL, tp->hint,
				     NULL)) {
      *buf_overflow = 1;
    }
  }
}


compliance_lookup(const char *name, int modid)
{
    if (modid == -1) {
        struct objgroup *op =
            (struct objgroup *) malloc(sizeof(struct objgroup));
        if (!op)
            return 0;
        op->next = objgroups;
        op->name = strdup(name);
        op->line = mibLine;
        objgroups = op;
        return 1;
    } else
        return find_tree_node(name, modid) != NULL;
}


is_labelchar(int ich)
{
    if ((isalnum(ich)) || (ich == '-'))
        return 1;
    if (ich == '_' && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
					     NETSNMP_DS_LIB_MIB_PARSE_LABEL)) {
        return 1;
    }

    return 0;
}


uptime_string_n(u_long timeticks, char *buf, size_t buflen)
{
    uptimeString(timeticks, buf, buflen);
    return buf;
}


print_ascii_dump(FILE * fp)
{
    fprintf(fp, "dump DEFINITIONS ::= BEGIN\n");
    print_ascii_dump_tree(fp, tree_head, 0);
    fprintf(fp, "END\n");
}


print_range_value(FILE * fp, int type, struct range_list * rp)
{
    switch (type) {
    case TYPE_INTEGER:
    case TYPE_INTEGER32:
        if (rp->low == rp->high)
            fprintf(fp, "%d", rp->low);
        else
            fprintf(fp, "%d..%d", rp->low, rp->high);
        break;
    case TYPE_UNSIGNED32:
    case TYPE_OCTETSTR:
    case TYPE_GAUGE:
    case TYPE_UINTEGER:
        if (rp->low == rp->high)
            fprintf(fp, "%u", (unsigned)rp->low);
        else
            fprintf(fp, "%u..%u", (unsigned)rp->low, (unsigned)rp->high);
        break;
    default:
        /* No other range types allowed */
        break;
    }
}


int __init rand_initialize(void)
{
	init_std_data(&input_pool);
	crng_initialize_primary(&primary_crng);
	crng_global_init_time = jiffies;
	if (ratelimit_disable) {
		urandom_warning.interval = 0;
		unseeded_warning.interval = 0;
	}
	return 0;
}


static void do_init_timer(struct timer_list *timer,
			  void (*func)(struct timer_list *),
			  unsigned int flags,
			  const char *name, struct lock_class_key *key)
{
	timer->entry.pprev = NULL;
	timer->function = func;
	timer->flags = flags | raw_smp_processor_id();
	lockdep_init_map(&timer->lockdep_map, name, key, 0);
}


void add_input_randomness(unsigned int type, unsigned int code,
				 unsigned int value)
{
	static unsigned char last_value;

	/* ignore autorepeat and the like */
	if (value == last_value)
		return;

	last_value = value;
	add_timer_randomness(&input_timer_state,
			     (type << 4) ^ code ^ (code >> 4) ^ value);
	trace_add_input_randomness(ENTROPY_BITS(&input_pool));
}


void add_disk_randomness(struct gendisk *disk)
{
	if (!disk || !disk->random)
		return;
	/* first major is 1, so we get >= 0x200 here */
	add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
	trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool));
}


static void _warn_unseeded_randomness(const char *func_name, void *caller,
				      void **previous)
{
#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM
	const bool print_once = false;
#else
	static bool print_once __read_mostly;
#endif

	if (print_once ||
	    crng_ready() ||
	    (previous && (caller == READ_ONCE(*previous))))
		return;
	WRITE_ONCE(*previous, caller);
#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM
	print_once = true;
#endif
	if (__ratelimit(&unseeded_warning))
		printk_deferred(KERN_NOTICE "random: %s called from %pS "
				"with crng_init=%d\n", func_name, caller,
				crng_init);
}


trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
{
	if (!is_timers_nohz_active())
		return;

	/*
	 * TODO: This wants some optimizing similar to the code below, but we
	 * will do that when we switch from push to pull for deferrable timers.
	 */
	if (timer->flags & TIMER_DEFERRABLE) {
		if (tick_nohz_full_cpu(base->cpu))
			wake_up_nohz_cpu(base->cpu);
		return;
	}

	/*
	 * We might have to IPI the remote CPU if the base is idle and the
	 * timer is not deferrable. If the other CPU is on the way to idle
	 * then it can't set base->is_idle as we hold the base lock:
	 */
	if (!base->is_idle)
		return;

	/* Check whether this is the new first expiring timer: */
	if (time_after_eq(timer->expires, base->next_expiry))
		return;

	/*
	 * Set the next expiry time and kick the CPU so it can reevaluate the
	 * wheel:
	 */
	if (time_before(timer->expires, base->clk)) {
		/*
		 * Prevent from forward_timer_base() moving the base->clk
		 * backward
		 */
		base->next_expiry = base->clk;
	} else {
		base->next_expiry = timer->expires;
	}
	wake_up_nohz_cpu(base->cpu);
}


int timers_dead_cpu(unsigned int cpu)
{
	struct timer_base *old_base;
	struct timer_base *new_base;
	int b, i;

	BUG_ON(cpu_online(cpu));

	for (b = 0; b < NR_BASES; b++) {
		old_base = per_cpu_ptr(&timer_bases[b], cpu);
		new_base = get_cpu_ptr(&timer_bases[b]);
		/*
		 * The caller is globally serialized and nobody else
		 * takes two locks at once, deadlock is not possible.
		 */
		raw_spin_lock_irq(&new_base->lock);
		raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);

		/*
		 * The current CPUs base clock might be stale. Update it
		 * before moving the timers over.
		 */
		forward_timer_base(new_base);

		BUG_ON(old_base->running_timer);

		for (i = 0; i < WHEEL_SIZE; i++)
			migrate_timer_list(new_base, old_base->vectors + i);

		raw_spin_unlock(&old_base->lock);
		raw_spin_unlock_irq(&new_base->lock);
		put_cpu_ptr(&timer_bases);
	}
	return 0;
}


static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
{
	sector_t status;
	u64 p_blkno = 0;
	int err = 0;
	struct inode *inode = mapping->host;

	trace_ocfs2_bmap((unsigned long long)OCFS2_I(inode)->ip_blkno,
			 (unsigned long long)block);

	/* We don't need to lock journal system files, since they aren't
	 * accessed concurrently from multiple nodes.
	 */
	if (!INODE_JOURNAL(inode)) {
		err = ocfs2_inode_lock(inode, NULL, 0);
		if (err) {
			if (err != -ENOENT)
				mlog_errno(err);
			goto bail;
		}
		down_read(&OCFS2_I(inode)->ip_alloc_sem);
	}

	if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
		err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
						  NULL);

	if (!INODE_JOURNAL(inode)) {
		up_read(&OCFS2_I(inode)->ip_alloc_sem);
		ocfs2_inode_unlock(inode, 0);
	}

	if (err) {
		mlog(ML_ERROR, "get_blocks() failed, block = %llu\n",
		     (unsigned long long)block);
		mlog_errno(err);
		goto bail;
	}

bail:
	status = err ? 0 : p_blkno;

	return status;
}


static int ocfs2_releasepage(struct page *page, gfp_t wait)
{
	journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal;

	if (!page_has_buffers(page))
		return 0;
	return jbd2_journal_try_to_free_buffers(journal, page, wait);
}


static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb,
					    u32 cpos,
					    unsigned int *start,
					    unsigned int *end)
{
	unsigned int cluster_start = 0, cluster_end = PAGE_CACHE_SIZE;

	if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits)) {
		unsigned int cpp;

		cpp = 1 << (PAGE_CACHE_SHIFT - osb->s_clustersize_bits);

		cluster_start = cpos % cpp;
		cluster_start = cluster_start << osb->s_clustersize_bits;

		cluster_end = cluster_start + osb->s_clustersize;
	}

	BUG_ON(cluster_start > PAGE_SIZE);
	BUG_ON(cluster_end > PAGE_SIZE);

	if (start)
		*start = cluster_start;
	if (end)
		*end = cluster_end;
}


lr_yum_use_local_load_base(LrHandle *handle,
                           LrResult *result,
                           LrYumRepo *repo,
                           LrYumRepoMd *repomd,
                           const gchar *baseurl,
                           GError **err)
{
    gboolean ret;
    GError *tmp_err = NULL;
    _cleanup_free_ gchar *path = NULL;
    _cleanup_free_ gchar *sig = NULL;
    _cleanup_fd_close_ int fd = -1;

    if (handle->mirrorlist_fd != -1) {
        // Locate mirrorlist if available.
        gchar *mrl_fn = lr_pathconcat(baseurl, "mirrorlist", NULL);
        if (g_file_test(mrl_fn, G_FILE_TEST_IS_REGULAR)) {
            g_debug("%s: Found local mirrorlist: %s", __func__, mrl_fn);
            repo->mirrorlist = mrl_fn;
        } else {
            repo->mirrorlist = NULL;
            lr_free(mrl_fn);
        }
    }

    if (handle->metalink_fd != -1) {
        // Locate metalink.xml if available.
        gchar *mtl_fn = lr_pathconcat(baseurl, "metalink.xml", NULL);
        if (g_file_test(mtl_fn, G_FILE_TEST_IS_REGULAR)) {
            g_debug("%s: Found local metalink: %s", __func__, mtl_fn);
            repo->metalink = mtl_fn;
        } else {
            repo->metalink = NULL;
            lr_free(mtl_fn);
        }
    }

    // Open repomd.xml
    path = lr_pathconcat(baseurl, "repodata/repomd.xml", NULL);
    fd = open(path, O_RDONLY);
    if (fd < 0) {
        g_debug("%s: open(%s): %s", __func__, path, g_strerror(errno));
        g_set_error(err, LR_YUM_ERROR, LRE_IO,
                    "Cannot open %s: %s", path, g_strerror(errno));
        return FALSE;
    }

    // Parse repomd.xml
    g_debug("%s: Parsing repomd.xml", __func__);
    ret = lr_yum_repomd_parse_file(repomd, fd, lr_xml_parser_warning_logger,
                                   "Repomd xml parser", &tmp_err);
    if (!ret) {
        g_debug("%s: Parsing unsuccessful: %s", __func__, tmp_err->message);
        g_propagate_prefixed_error(err, tmp_err,
                                   "repomd.xml parser error: ");
        return FALSE;
    }

    // Fill result object
    result->destdir = g_strdup(baseurl);
    repo->destdir = g_strdup(baseurl);
    repo->repomd = g_strdup(path);

    // Check if signature file exists
    sig = lr_pathconcat(baseurl, "repodata/repomd.xml.asc", NULL);
    if (access(sig, F_OK) == 0)
        repo->signature = g_strdup(sig);

    // Signature checking
    if (handle->checks & LR_CHECK_GPG) {

        if (!repo->signature) {
            // Signature doesn't exist
            g_set_error(err, LR_YUM_ERROR, LRE_BADGPG,
                        "GPG verification is enabled, but GPG signature "
                        "repomd.xml.asc is not available. This may be an "
                        "error or the repository does not support GPG verification.");
            return FALSE;
        }

        ret = lr_gpg_check_signature(repo->signature,
                                     repo->repomd,
                                     handle->gnupghomedir,
                                     &tmp_err);
        if (!ret) {
            g_debug("%s: repomd.xml GPG signature verification failed: %s",
                    __func__, tmp_err->message);
            g_propagate_prefixed_error(err, tmp_err,
                        "repomd.xml GPG signature verification failed: ");
            return FALSE;
        }
    }

    // Done - repomd is loaded and checked
    g_debug("%s: Repomd revision: %s", __func__, repomd->revision);

    return TRUE;
}


cbdata_free(CbData *data)
{
    if (!data) return;
    free(data->metadata);
    free(data);
}


lr_copy_metalink_content(LrHandle *handle,
                         LrYumRepo *repo,
                         GError **err)
{
    int fd;
    int rc;

    if (handle->metalink_fd != -1) {
        char *ml_file_path = lr_pathconcat(handle->destdir,
                                           "metalink.xml", NULL);
        fd = open(ml_file_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
        if (fd < 0) {
            g_debug("%s: Cannot create: %s", __func__, ml_file_path);
            g_set_error(err, LR_YUM_ERROR, LRE_IO,
                        "Cannot create %s: %s", ml_file_path, g_strerror(errno));
            lr_free(ml_file_path);
            return FALSE;
        }
        rc = lr_copy_content(handle->metalink_fd, fd);
        close(fd);
        if (rc != 0) {
            g_debug("%s: Cannot copy content of metalink file", __func__);
            g_set_error(err, LR_YUM_ERROR, LRE_IO,
                        "Cannot copy content of metalink file %s: %s",
                        ml_file_path, g_strerror(errno));
            lr_free(ml_file_path);
            return FALSE;
        }
        repo->metalink = ml_file_path;
    }

    return TRUE;
}


static int read_sep(link_ctx *ctx)
{
    if (skip_ws(ctx) && read_chr(ctx, ',')) {
        return 1;
    }
    return 0;
}


static int add_push(link_ctx *ctx)
{
    /* so, we have read a Link header and need to decide
     * if we transform it into a push.
     */
    if (has_relation(ctx, "preload") && !has_param(ctx, "nopush")) {
        apr_uri_t uri;
        if (apr_uri_parse(ctx->pool, ctx->link, &uri) == APR_SUCCESS) {
            if (uri.path && same_authority(ctx->req, &uri)) {
                char *path;
                const char *method;
                apr_table_t *headers;
                h2_request *req;
                h2_push *push;

                /* We only want to generate pushes for resources in the
                 * same authority than the original request.
                 * icing: i think that is wise, otherwise we really need to
                 * check that the vhost/server is available and uses the same
                 * TLS (if any) parameters.
                 */
                path = apr_uri_unparse(ctx->pool, &uri, APR_URI_UNP_OMITSITEPART);
                push = apr_pcalloc(ctx->pool, sizeof(*push));
                switch (ctx->push_policy) {
                    case H2_PUSH_HEAD:
                        method = "HEAD";
                        break;
                    default:
                        method = "GET";
                        break;
                }
                headers = apr_table_make(ctx->pool, 5);
                apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
                req = h2_req_create(0, ctx->pool, method, ctx->req->scheme,
                                    ctx->req->authority, path, headers,
                                    ctx->req->serialize);
                /* atm, we do not push on pushes */
                h2_request_end_headers(req, ctx->pool, 1, 0);
                push->req = req;
                if (has_param(ctx, "critical")) {
                    h2_priority *prio = apr_pcalloc(ctx->pool, sizeof(*prio));
                    prio->dependency = H2_DEPENDANT_BEFORE;
                    push->priority = prio;
                }
                if (!ctx->pushes) {
                    ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
                }
                APR_ARRAY_PUSH(ctx->pushes, h2_push*) = push;
            }
        }
    }
    return 0;
}


apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *pool,
                                      int maxP, const char *authority,
                                      const char **pdata, apr_size_t *plen)
{
    int nelts, N, i;
    unsigned char log2n, log2pmax;
    gset_encoder encoder;
    apr_uint64_t *hashes;
    apr_size_t hash_count;

    nelts = diary->entries->nelts;
    N = ceil_power_of_2(nelts);
    log2n = h2_log2(N);

    /* Now log2p is the max number of relevant bits, so that
     * log2p + log2n == mask_bits. We can use a lower log2p
     * and have a shorter set encoding...
     */
    log2pmax = h2_log2(ceil_power_of_2(maxP));

    memset(&encoder, 0, sizeof(encoder));
    encoder.diary = diary;
    encoder.log2p = H2MIN(diary->mask_bits - log2n, log2pmax);
    encoder.mask_bits = log2n + encoder.log2p;
    encoder.delta_bits = diary->mask_bits - encoder.mask_bits;
    encoder.fixed_bits = encoder.log2p;
    encoder.fixed_mask = 1;
    encoder.fixed_mask = (encoder.fixed_mask << encoder.fixed_bits) - 1;
    encoder.pool = pool;
    encoder.datalen = 512;
    encoder.data = apr_pcalloc(encoder.pool, encoder.datalen);

    encoder.data[0] = log2n;
    encoder.data[1] = encoder.log2p;
    encoder.offset = 1;
    encoder.bit = 8;
    encoder.last = 0;

    /* Intentional no APLOGNO */
    ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
                  "h2_push_diary_digest_get: %d entries, N=%d, log2n=%d, "
                  "mask_bits=%d, enc.mask_bits=%d, delta_bits=%d, enc.log2p=%d, authority=%s",
                  (int)nelts, (int)N, (int)log2n, diary->mask_bits,
                  (int)encoder.mask_bits, (int)encoder.delta_bits,
                  (int)encoder.log2p, authority);

    if (!authority || !diary->authority
        || !strcmp("*", authority) || !strcmp(diary->authority, authority)) {
        hash_count = diary->entries->nelts;
        hashes = apr_pcalloc(encoder.pool, hash_count);
        for (i = 0; i < hash_count; ++i) {
            hashes[i] = ((&APR_ARRAY_IDX(diary->entries, i, h2_push_diary_entry))->hash
                         >> encoder.delta_bits);
        }

        qsort(hashes, hash_count, sizeof(apr_uint64_t), cmp_puint64);
        for (i = 0; i < hash_count; ++i) {
            if (!i || (hashes[i] != hashes[i-1])) {
                gset_encode_next(&encoder, hashes[i]);
            }
        }
        /* Intentional no APLOGNO */
        ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
                      "h2_push_diary_digest_get: golomb compressed hashes, %d bytes",
                      (int)encoder.offset + 1);
    }
    *pdata = (const char *)encoder.data;
    *plen = encoder.offset + 1;

    return APR_SUCCESS;
}


static int read_ptoken(link_ctx *ctx, const char **ps)
{
    if (skip_ws(ctx)) {
        size_t i;
        for (i = ctx->i; i < ctx->slen && ptoken_char(ctx->s[i]); ++i) {
            /* nop */
        }
        if (i > ctx->i) {
            *ps = mk_str(ctx, i);
            ctx->i = i;
            return 1;
        }
    }
    return 0;
}


static int same_authority(const h2_request *req, const apr_uri_t *uri)
{
    if (uri->scheme != NULL && strcmp(uri->scheme, req->scheme)) {
        return 0;
    }
    if (uri->hostinfo != NULL && strcmp(uri->hostinfo, req->authority)) {
        return 0;
    }
    return 1;
}


static void remove_first(h2_push_diary *diary)
{
    h2_push_diary_entry *entries = (h2_push_diary_entry*)diary->entries->elts;
    int lastidx;

    /* move remaining entries to index 0 */
    lastidx = diary->entries->nelts - 1;
    if (lastidx > 0) {
        --diary->entries->nelts;
        memmove(entries, entries+1, sizeof(h2_push_diary_entry) * diary->entries->nelts);
    }
}


apr_array_header_t *h2_push_collect_update(h2_stream *stream,
                                           const struct h2_request *req,
                                           const struct h2_headers *res)
{
    apr_array_header_t *pushes;

    pushes = h2_push_collect(stream->pool, req, stream->push_policy, res);
    return h2_push_diary_update(stream->session, pushes);
}


static unsigned int val_apr_hash(const char *str)
{
    apr_ssize_t len = (apr_ssize_t)strlen(str);
    return apr_hashfunc_default(str, &len);
}


struct ares_addrinfo_node *ares__append_addrinfo_node(struct ares_addrinfo_node **head)
{
  struct ares_addrinfo_node *tail = ares__malloc_addrinfo_node();
  struct ares_addrinfo_node *last = *head;
  if (!last)
    {
      *head = tail;
      return tail;
    }

  while (last->ai_next)
    {
      last = last->ai_next;
    }

  last->ai_next = tail;
  return tail;
}


static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	struct sock *sk = sock->sk;
	int err;

	IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd);

	err = -EINVAL;
	switch (cmd) {
	case TIOCOUTQ: {
		long amount;

		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
		if (amount < 0)
			amount = 0;
		err = put_user(amount, (unsigned int __user *)arg);
		break;
	}

	case TIOCINQ: {
		struct sk_buff *skb;
		long amount = 0L;
		/* These two are safe on a single CPU system as only user tasks fiddle here */
		if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
			amount = skb->len;
		err = put_user(amount, (unsigned int __user *)arg);
		break;
	}

	case SIOCGSTAMP:
		if (sk != NULL)
			err = sock_get_timestamp(sk, (struct timeval __user *)arg);
		break;

	case SIOCGIFADDR:
	case SIOCSIFADDR:
	case SIOCGIFDSTADDR:
	case SIOCSIFDSTADDR:
	case SIOCGIFBRDADDR:
	case SIOCSIFBRDADDR:
	case SIOCGIFNETMASK:
	case SIOCSIFNETMASK:
	case SIOCGIFMETRIC:
	case SIOCSIFMETRIC:
		break;
	default:
		IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__);
		err = -ENOIOCTLCMD;
	}

	return err;
}


static int irda_setsockopt(struct socket *sock, int level, int optname,
			   char __user *optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	struct irda_sock *self = irda_sk(sk);
	struct irda_ias_set    *ias_opt;
	struct ias_object      *ias_obj;
	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
	int opt, free_ias = 0, err = 0;

	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);

	if (level != SOL_IRLMP)
		return -ENOPROTOOPT;

	lock_sock(sk);

	switch (optname) {
	case IRLMP_IAS_SET:
		/* The user want to add an attribute to an existing IAS object
		 * (in the IAS database) or to create a new object with this
		 * attribute.
		 * We first query IAS to know if the object exist, and then
		 * create the right attribute...
		 */

		if (optlen != sizeof(struct irda_ias_set)) {
			err = -EINVAL;
			goto out;
		}

		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
		if (ias_opt == NULL) {
			err = -ENOMEM;
			goto out;
		}

		/* Copy query to the driver. */
		if (copy_from_user(ias_opt, optval, optlen)) {
			kfree(ias_opt);
			err = -EFAULT;
			goto out;
		}

		/* Find the object we target.
		 * If the user gives us an empty string, we use the object
		 * associated with this socket. This will workaround
		 * duplicated class name - Jean II */
		if(ias_opt->irda_class_name[0] == '\0') {
			if(self->ias_obj == NULL) {
				kfree(ias_opt);
				err = -EINVAL;
				goto out;
			}
			ias_obj = self->ias_obj;
		} else
			ias_obj = irias_find_object(ias_opt->irda_class_name);

		/* Only ROOT can mess with the global IAS database.
		 * Users can only add attributes to the object associated
		 * with the socket they own - Jean II */
		if((!capable(CAP_NET_ADMIN)) &&
		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
			kfree(ias_opt);
			err = -EPERM;
			goto out;
		}

		/* If the object doesn't exist, create it */
		if(ias_obj == (struct ias_object *) NULL) {
			/* Create a new object */
			ias_obj = irias_new_object(ias_opt->irda_class_name,
						   jiffies);
			if (ias_obj == NULL) {
				kfree(ias_opt);
				err = -ENOMEM;
				goto out;
			}
			free_ias = 1;
		}

		/* Do we have the attribute already ? */
		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
			kfree(ias_opt);
			if (free_ias) {
				kfree(ias_obj->name);
				kfree(ias_obj);
			}
			err = -EINVAL;
			goto out;
		}

		/* Look at the type */
		switch(ias_opt->irda_attrib_type) {
		case IAS_INTEGER:
			/* Add an integer attribute */
			irias_add_integer_attrib(
				ias_obj,
				ias_opt->irda_attrib_name,
				ias_opt->attribute.irda_attrib_int,
				IAS_USER_ATTR);
			break;
		case IAS_OCT_SEQ:
			/* Check length */
			if(ias_opt->attribute.irda_attrib_octet_seq.len >
			   IAS_MAX_OCTET_STRING) {
				kfree(ias_opt);
				if (free_ias) {
					kfree(ias_obj->name);
					kfree(ias_obj);
				}

				err = -EINVAL;
				goto out;
			}
			/* Add an octet sequence attribute */
			irias_add_octseq_attrib(
			      ias_obj,
			      ias_opt->irda_attrib_name,
			      ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
			      ias_opt->attribute.irda_attrib_octet_seq.len,
			      IAS_USER_ATTR);
			break;
		case IAS_STRING:
			/* Should check charset & co */
			/* Check length */
			/* The length is encoded in a __u8, and
			 * IAS_MAX_STRING == 256, so there is no way
			 * userspace can pass us a string too large.
			 * Jean II */
			/* NULL terminate the string (avoid troubles) */
			ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0';
			/* Add a string attribute */
			irias_add_string_attrib(
				ias_obj,
				ias_opt->irda_attrib_name,
				ias_opt->attribute.irda_attrib_string.string,
				IAS_USER_ATTR);
			break;
		default :
			kfree(ias_opt);
			if (free_ias) {
				kfree(ias_obj->name);
				kfree(ias_obj);
			}
			err = -EINVAL;
			goto out;
		}
		irias_insert_object(ias_obj);
		kfree(ias_opt);
		break;
	case IRLMP_IAS_DEL:
		/* The user want to delete an object from our local IAS
		 * database. We just need to query the IAS, check is the
		 * object is not owned by the kernel and delete it.
		 */

		if (optlen != sizeof(struct irda_ias_set)) {
			err = -EINVAL;
			goto out;
		}

		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
		if (ias_opt == NULL) {
			err = -ENOMEM;
			goto out;
		}

		/* Copy query to the driver. */
		if (copy_from_user(ias_opt, optval, optlen)) {
			kfree(ias_opt);
			err = -EFAULT;
			goto out;
		}

		/* Find the object we target.
		 * If the user gives us an empty string, we use the object
		 * associated with this socket. This will workaround
		 * duplicated class name - Jean II */
		if(ias_opt->irda_class_name[0] == '\0')
			ias_obj = self->ias_obj;
		else
			ias_obj = irias_find_object(ias_opt->irda_class_name);
		if(ias_obj == (struct ias_object *) NULL) {
			kfree(ias_opt);
			err = -EINVAL;
			goto out;
		}

		/* Only ROOT can mess with the global IAS database.
		 * Users can only del attributes from the object associated
		 * with the socket they own - Jean II */
		if((!capable(CAP_NET_ADMIN)) &&
		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
			kfree(ias_opt);
			err = -EPERM;
			goto out;
		}

		/* Find the attribute (in the object) we target */
		ias_attr = irias_find_attrib(ias_obj,
					     ias_opt->irda_attrib_name);
		if(ias_attr == (struct ias_attrib *) NULL) {
			kfree(ias_opt);
			err = -EINVAL;
			goto out;
		}

		/* Check is the user space own the object */
		if(ias_attr->value->owner != IAS_USER_ATTR) {
			IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__);
			kfree(ias_opt);
			err = -EPERM;
			goto out;
		}

		/* Remove the attribute (and maybe the object) */
		irias_delete_attrib(ias_obj, ias_attr, 1);
		kfree(ias_opt);
		break;
	case IRLMP_MAX_SDU_SIZE:
		if (optlen < sizeof(int)) {
			err = -EINVAL;
			goto out;
		}

		if (get_user(opt, (int __user *)optval)) {
			err = -EFAULT;
			goto out;
		}

		/* Only possible for a seqpacket service (TTP with SAR) */
		if (sk->sk_type != SOCK_SEQPACKET) {
			IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n",
				   __func__, opt);
			self->max_sdu_size_rx = opt;
		} else {
			IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
				     __func__);
			err = -ENOPROTOOPT;
			goto out;
		}
		break;
	case IRLMP_HINTS_SET:
		if (optlen < sizeof(int)) {
			err = -EINVAL;
			goto out;
		}

		/* The input is really a (__u8 hints[2]), easier as an int */
		if (get_user(opt, (int __user *)optval)) {
			err = -EFAULT;
			goto out;
		}

		/* Unregister any old registration */
		if (self->skey)
			irlmp_unregister_service(self->skey);

		self->skey = irlmp_register_service((__u16) opt);
		break;
	case IRLMP_HINT_MASK_SET:
		/* As opposed to the previous case which set the hint bits
		 * that we advertise, this one set the filter we use when
		 * making a discovery (nodes which don't match any hint
		 * bit in the mask are not reported).
		 */
		if (optlen < sizeof(int)) {
			err = -EINVAL;
			goto out;
		}

		/* The input is really a (__u8 hints[2]), easier as an int */
		if (get_user(opt, (int __user *)optval)) {
			err = -EFAULT;
			goto out;
		}

		/* Set the new hint mask */
		self->mask.word = (__u16) opt;
		/* Mask out extension bits */
		self->mask.word &= 0x7f7f;
		/* Check if no bits */
		if(!self->mask.word)
			self->mask.word = 0xFFFF;

		break;
	default:
		err = -ENOPROTOOPT;
		break;
	}

out:
	release_sock(sk);

	return err;
}


static int netns_exec(int argc, char **argv)
{
	/* Setup the proper environment for apps that are not netns
	 * aware, and execute a program in that environment.
	 */
	const char *cmd;

	if (argc < 1 && !do_all) {
		fprintf(stderr, "No netns name specified\n");
		return -1;
	}
	if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
		fprintf(stderr, "No command specified\n");
		return -1;
	}

	if (do_all)
		return do_each_netns(on_netns_exec, --argv, 1);

	if (netns_switch(argv[0]))
		return -1;

	/* we just changed namespaces. clear any vrf association
	 * with prior namespace before exec'ing command
	 */
	vrf_reset();

	/* ip must return the status of the child,
	 * but do_cmd() will add a minus to this,
	 * so let's add another one here to cancel it.
	 */
	cmd = argv[1];
	return -cmd_exec(cmd, argv + 1, !!batch_mode);
}


static int netns_list_id(int argc, char **argv)
{
	if (!ipnetns_have_nsid()) {
		fprintf(stderr,
			"RTM_GETNSID is not supported by the kernel.\n");
		return -ENOTSUP;
	}

	if (rtnl_nsiddump_req(&rth, AF_UNSPEC) < 0) {
		perror("Cannot send dump request");
		exit(1);
	}

	new_json_obj(json);
	if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
		delete_json_obj();
		fprintf(stderr, "Dump terminated\n");
		exit(1);
	}
	delete_json_obj();
	return 0;
}


int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
                uint8_t *line, unsigned int num_lines, int stride,
                uint32_t *io_ptr, unsigned int num_io_words)
{
    Encoder *encoder = (Encoder *)quic;
    uint32_t *io_ptr_end = io_ptr + num_io_words;
    uint8_t *lines_end;
    int row;
    uint8_t *prev;
    int channels;
    int bpc;

    lines_end = line + num_lines * stride;
    if (line == NULL && lines_end != line) {
        spice_warn_if_reached();
        return QUIC_ERROR;
    }

    quic_image_params(encoder, type, &channels, &bpc);

    if (!encoder_reset(encoder, io_ptr, io_ptr_end) ||
        !encoder_reset_channels(encoder, channels, width, bpc)) {
        return QUIC_ERROR;
    }

    encoder->io_word = 0;
    encoder->io_available_bits = 32;

    encode_32(encoder, QUIC_MAGIC);
    encode_32(encoder, QUIC_VERSION);
    encode_32(encoder, type);
    encode_32(encoder, width);
    encode_32(encoder, height);

    FILL_LINES();

    switch (type) {
    case QUIC_IMAGE_TYPE_RGB32:
        spice_assert(ABS(stride) >= width * 4);
        QUIC_COMPRESS_RGB(32);
        break;
    case QUIC_IMAGE_TYPE_RGB24:
        spice_assert(ABS(stride) >= width * 3);
        QUIC_COMPRESS_RGB(24);
        break;
    case QUIC_IMAGE_TYPE_RGB16:
        spice_assert(ABS(stride) >= width * 2);
        QUIC_COMPRESS_RGB(16);
        break;
    case QUIC_IMAGE_TYPE_RGBA:
        spice_assert(ABS(stride) >= width * 4);

        encoder->channels[0].correlate_row[-1] = 0;
        encoder->channels[1].correlate_row[-1] = 0;
        encoder->channels[2].correlate_row[-1] = 0;
        quic_rgb32_compress_row0(encoder, (rgb32_pixel_t *)(line), width);

        encoder->channels[3].correlate_row[-1] = 0;
        quic_four_compress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(line + 3), width);

        encoder->rows_completed++;

        for (row = 1; row < height; row++) {
            prev = line;
            NEXT_LINE();
            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
            quic_rgb32_compress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)line, width);

            encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
            quic_four_compress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
                                   (four_bytes_t *)(line + 3), width);
            encoder->rows_completed++;
        }
        break;
    case QUIC_IMAGE_TYPE_GRAY:
        spice_assert(ABS(stride) >= width);
        encoder->channels[0].correlate_row[-1] = 0;
        quic_one_compress_row0(encoder, &encoder->channels[0], (one_byte_t *)line, width);
        encoder->rows_completed++;
        for (row = 1; row < height; row++) {
            prev = line;
            NEXT_LINE();
            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
            quic_one_compress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
                                  (one_byte_t *)line, width);
            encoder->rows_completed++;
        }
        break;
    case QUIC_IMAGE_TYPE_INVALID:
    default:
        encoder->usr->error(encoder->usr, "bad image type\n");
    }

    flush(encoder);
    encoder->io_words_count -= (encoder->io_end - encoder->io_now);

    return encoder->io_words_count;
}


static int encoder_reset(Encoder *encoder, uint32_t *io_ptr, uint32_t *io_ptr_end)
{
    spice_assert(((uintptr_t)io_ptr % 4) == ((uintptr_t)io_ptr_end % 4));
    spice_assert(io_ptr <= io_ptr_end);

    encoder->rgb_state.waitcnt = 0;
    encoder->rgb_state.tabrand_seed = stabrand();
    encoder->rgb_state.wmidx = DEFwmistart;
    encoder->rgb_state.wmileft = DEFwminext;
    set_wm_trigger(&encoder->rgb_state);

    encoder_init_rle(&encoder->rgb_state);

    encoder->io_words_count = io_ptr_end - io_ptr;
    encoder->io_now = io_ptr;
    encoder->io_end = io_ptr_end;
    encoder->rows_completed = 0;

    return TRUE;
}


static inline void decode_eat32bits(Encoder *encoder)
{
    decode_eatbits(encoder, 16);
    decode_eatbits(encoder, 16);
}


static inline void encode_ones(Encoder *encoder, unsigned int n)
{
    unsigned int count;

    for (count = n >> 5; count; count--) {
        encode_32(encoder, ~0U);
    }

    if ((n &= 0x1f)) {
        encode(encoder, (1U << n) - 1, n);
    }
}


static unsigned int tabrand(unsigned int *tabrand_seed)
{
    return tabrand_chaos[++*tabrand_seed & TABRAND_SEEDMASK];
}


static int decode_state_run(Encoder *encoder, CommonState *state)
{
    int runlen = 0;

    do {
        register int temp, hits;
        temp = lzeroes[(BYTE)(~(encoder->io_word >> 24))];/* number of leading ones in the
                                                                      input stream, up to 8 */
        for (hits = 1; hits <= temp; hits++) {
            runlen += state->melcorder;

            if (state->melcstate < MELCSTATES - 1) {
                state->melclen = J[++state->melcstate];
                state->melcorder = (1U << state->melclen);
            }
        }
        if (temp != 8) {
            decode_eatbits(encoder, temp + 1);  /* consume the leading
                                                            0 of the remainder encoding */
            break;
        }
        decode_eatbits(encoder, 8);
    } while (1);

    /* read the length of the remainder */
    if (state->melclen) {
        runlen += encoder->io_word >> (32 - state->melclen);
        decode_eatbits(encoder, state->melclen);
    }

    /* adjust melcorder parameters */
    if (state->melcstate) {
        state->melclen = J[--state->melcstate];
        state->melcorder = (1U << state->melclen);
    }

    return runlen;
}


int quic_decode_begin(QuicContext *quic, uint32_t *io_ptr, unsigned int num_io_words,
                      QuicImageType *out_type, int *out_width, int *out_height)
{
    Encoder *encoder = (Encoder *)quic;
    uint32_t *io_ptr_end = io_ptr + num_io_words;
    QuicImageType type;
    int width;
    int height;
    uint32_t magic;
    uint32_t version;
    int channels;
    int bpc;

    if (!num_io_words || !encoder_reset(encoder, io_ptr, io_ptr_end)) {
        return QUIC_ERROR;
    }

    init_decode_io(encoder);

    magic = encoder->io_word;
    decode_eat32bits(encoder);
    if (magic != QUIC_MAGIC) {
        encoder->usr->warn(encoder->usr, "bad magic\n");
        return QUIC_ERROR;
    }

    version = encoder->io_word;
    decode_eat32bits(encoder);
    if (version != QUIC_VERSION) {
        encoder->usr->warn(encoder->usr, "bad version\n");
        return QUIC_ERROR;
    }

    type = (QuicImageType)encoder->io_word;
    decode_eat32bits(encoder);

    width = encoder->io_word;
    decode_eat32bits(encoder);

    height = encoder->io_word;
    decode_eat32bits(encoder);

    if (width <= 0 || height <= 0) {
        encoder->usr->warn(encoder->usr, "invalid size\n");
        return QUIC_ERROR;
    }

    /* avoid too big images */
    if ((uint64_t) width * height > SPICE_MAX_IMAGE_SIZE) {
        encoder->usr->error(encoder->usr, "image too large\n");
    }

    quic_image_params(encoder, type, &channels, &bpc);

    if (!encoder_reset_channels(encoder, channels, width, bpc)) {
        return QUIC_ERROR;
    }

    *out_width = encoder->width = width;
    *out_height = encoder->height = height;
    *out_type = encoder->type = type;
    return QUIC_OK;
}


static void FNAME_DECL(uncompress_row)(const PIXEL * const prev_row,
                                       PIXEL * const cur_row,
                                       unsigned int width)

{
    DECLARE_STATE_VARIABLES;
    const unsigned int bpc_mask = BPC_MASK;
    unsigned int pos = 0;

    while ((DEFwmimax > (int)state->wmidx) && (state->wmileft <= width)) {
        if (state->wmileft) {
            FNAME_CALL(uncompress_row_seg)(prev_row, cur_row, pos,
                                           pos + state->wmileft, bpc_mask);
            pos += state->wmileft;
            width -= state->wmileft;
        }

        state->wmidx++;
        set_wm_trigger(state);
        state->wmileft = DEFwminext;
    }

    if (width) {
        FNAME_CALL(uncompress_row_seg)(prev_row, cur_row, pos,
                                       pos + width, bpc_mask);
        if (DEFwmimax > (int)state->wmidx) {
            state->wmileft -= width;
        }
    }

    spice_assert((int)state->wmidx <= DEFwmimax);
    spice_assert(state->wmidx <= 32);
    spice_assert(DEFwminext > 0);
}


static void FNAME_DECL(uncompress_row_seg)(const PIXEL * const prev_row,
                                           PIXEL * const cur_row,
                                           int i,
                                           const int end,
                                           const unsigned int bpc_mask)
{
    DECLARE_STATE_VARIABLES;
    DECLARE_CHANNEL_VARIABLES;
    const unsigned int waitmask = bppmask[state->wmidx];
    int stopidx;
    int run_index = 0;
    int run_end;

    spice_assert(end - i > 0);

    if (i == 0) {
        unsigned int codewordlen;

        UNCOMPRESS_PIX_START(&cur_row[i]);
        APPLY_ALL_COMP(UNCOMPRESS_ONE_0);

        if (state->waitcnt) {
            --state->waitcnt;
        } else {
            state->waitcnt = (tabrand(&state->tabrand_seed) & waitmask);
            UPDATE_MODEL(0);
        }
        stopidx = ++i + state->waitcnt;
    } else {
        stopidx = i + state->waitcnt;
    }
    for (;;) {
        while (stopidx < end) {
            for (; i <= stopidx; i++) {
                unsigned int codewordlen;
                RLE_PRED_IMP;
                UNCOMPRESS_PIX_START(&cur_row[i]);
                APPLY_ALL_COMP(UNCOMPRESS_ONE);
            }

            UPDATE_MODEL(stopidx);

            stopidx = i + (tabrand(&state->tabrand_seed) & waitmask);
        }

        for (; i < end; i++) {
            unsigned int codewordlen;
            RLE_PRED_IMP;
            UNCOMPRESS_PIX_START(&cur_row[i]);
            APPLY_ALL_COMP(UNCOMPRESS_ONE);
        }

        state->waitcnt = stopidx - end;

        return;

do_run:
        state->waitcnt = stopidx - i;
        run_index = i;
        run_end = decode_state_run(encoder, state);
        if (run_end < 0 || run_end > (end - i)) {
            encoder->usr->error(encoder->usr, "wrong RLE\n");
        }
        run_end += i;

        for (; i < run_end; i++) {
            UNCOMPRESS_PIX_START(&cur_row[i]);
            COPY_PIXEL(&cur_row[i], &cur_row[i - 1]);
        }

        if (i == end) {
            return;
        }

        stopidx = i + state->waitcnt;
    }
}


static void FNAME_DECL(compress_row_seg)(int i,
                                         const PIXEL * const prev_row,
                                         const PIXEL * const cur_row,
                                         const int end,
                                         const unsigned int waitmask,
                                         const unsigned int bpc_mask)
{
    DECLARE_STATE_VARIABLES;
    DECLARE_CHANNEL_VARIABLES;
    int stopidx;
    int run_index = 0;
    int run_size;

    spice_assert(end - i > 0);

    if (i == 0) {
        APPLY_ALL_COMP(COMPRESS_ONE_0);

        if (state->waitcnt) {
            state->waitcnt--;
        } else {
            state->waitcnt = (tabrand(&state->tabrand_seed) & waitmask);
            UPDATE_MODEL(0);
        }
        stopidx = ++i + state->waitcnt;
    } else {
        stopidx = i + state->waitcnt;
    }
    for (;;) {
        while (stopidx < end) {
            for (; i <= stopidx; i++) {
                RLE_PRED_IMP;
                APPLY_ALL_COMP(COMPRESS_ONE, i);
            }

            UPDATE_MODEL(stopidx);
            stopidx = i + (tabrand(&state->tabrand_seed) & waitmask);
        }

        for (; i < end; i++) {
            RLE_PRED_IMP;
            APPLY_ALL_COMP(COMPRESS_ONE, i);
        }
        state->waitcnt = stopidx - end;

        return;

do_run:
        run_index = i;
        state->waitcnt = stopidx - i;
        run_size = 0;

        while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
            run_size++;
            if (++i == end) {
                encode_state_run(encoder, state, run_size);
                return;
            }
        }
        encode_state_run(encoder, state, run_size);
        stopidx = i + state->waitcnt;
    }
}


static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
{
    spice_extra_assert(val < (0x1U << BPC));

    /* The and (&) here is to avoid buffer overflows in case of garbage or malicious
     * attempts. Is much faster then using comparisons and save us from such situations.
     * Note that on normal build the check above won't be compiled as this code path
     * is pretty hot and would cause speed regressions.
     */
    return channel->_buckets_ptrs[val & ((1U << BPC) - 1)];
}


nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
	   struct kvec *vec, int vlen, unsigned long *cnt, int stable,
	   __be32 *verf)
{
	struct nfsd_file *nf;
	__be32 err;

	trace_nfsd_write_start(rqstp, fhp, offset, *cnt);

	err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf);
	if (err)
		goto out;

	err = nfsd_vfs_write(rqstp, fhp, nf, offset, vec,
			vlen, cnt, stable, verf);
	nfsd_file_put(nf);
out:
	trace_nfsd_write_done(rqstp, fhp, offset, *cnt);
	return err;
}


nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
				char *fname, int flen,
				char *path,
				struct svc_fh *resfhp)
{
	struct dentry	*dentry, *dnew;
	__be32		err, cerr;
	int		host_err;

	err = nfserr_noent;
	if (!flen || path[0] == '\0')
		goto out;
	err = nfserr_exist;
	if (isdotent(fname, flen))
		goto out;

	err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
	if (err)
		goto out;

	host_err = fh_want_write(fhp);
	if (host_err)
		goto out_nfserr;

	fh_lock(fhp);
	dentry = fhp->fh_dentry;
	dnew = lookup_one_len(fname, dentry, flen);
	host_err = PTR_ERR(dnew);
	if (IS_ERR(dnew))
		goto out_nfserr;

	host_err = vfs_symlink(d_inode(dentry), dnew, path);
	err = nfserrno(host_err);
	if (!err)
		err = nfserrno(commit_metadata(fhp));
	fh_unlock(fhp);

	fh_drop_write(fhp);

	cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
	dput(dnew);
	if (err==0) err = cerr;
out:
	return err;

out_nfserr:
	err = nfserrno(host_err);
	goto out;
}


SProcXkbGetIndicatorState(ClientPtr client)
{
    REQUEST(xkbGetIndicatorStateReq);

    swaps(&stuff->length);
    REQUEST_SIZE_MATCH(xkbGetIndicatorStateReq);
    swaps(&stuff->deviceSpec);
    return ProcXkbGetIndicatorState(client);
}


SProcXkbLatchLockState(ClientPtr client)
{
    REQUEST(xkbLatchLockStateReq);

    swaps(&stuff->length);
    REQUEST_SIZE_MATCH(xkbLatchLockStateReq);
    swaps(&stuff->deviceSpec);
    swaps(&stuff->groupLatch);
    return ProcXkbLatchLockState(client);
}


RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient,
                       int category, void *data, int datalen, int padlen,
                       int futurelen)
{
    CARD32 elemHeaderData[2];
    int numElemHeaders = 0;
    Bool recordingClientSwapped = pContext->pRecordingClient->swapped;
    CARD32 serverTime = 0;
    Bool gotServerTime = FALSE;
    int replylen;

    if (futurelen >= 0) {       /* start of new protocol element */
        xRecordEnableContextReply *pRep = (xRecordEnableContextReply *)
            pContext->replyBuffer;

        if (pContext->pBufClient != pClient ||
            pContext->bufCategory != category) {
            RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
            pContext->pBufClient = pClient;
            pContext->bufCategory = category;
        }

        if (!pContext->numBufBytes) {
            serverTime = GetTimeInMillis();
            gotServerTime = TRUE;
            pRep->type = X_Reply;
            pRep->category = category;
            pRep->sequenceNumber = pContext->pRecordingClient->sequence;
            pRep->length = 0;
            pRep->elementHeader = pContext->elemHeaders;
            pRep->serverTime = serverTime;
            if (pClient) {
                pRep->clientSwapped =
                    (pClient->swapped != recordingClientSwapped);
                pRep->idBase = pClient->clientAsMask;
                pRep->recordedSequenceNumber = pClient->sequence;
            }
            else {              /* it's a device event, StartOfData, or EndOfData */

                pRep->clientSwapped = (category != XRecordFromServer) &&
                    recordingClientSwapped;
                pRep->idBase = 0;
                pRep->recordedSequenceNumber = 0;
            }

            if (recordingClientSwapped) {
                swaps(&pRep->sequenceNumber);
                swapl(&pRep->length);
                swapl(&pRep->idBase);
                swapl(&pRep->serverTime);
                swapl(&pRep->recordedSequenceNumber);
            }
            pContext->numBufBytes = SIZEOF(xRecordEnableContextReply);
        }

        /* generate element headers if needed */

        if (((pContext->elemHeaders & XRecordFromClientTime)
             && category == XRecordFromClient)
            || ((pContext->elemHeaders & XRecordFromServerTime)
                && category == XRecordFromServer)) {
            if (gotServerTime)
                elemHeaderData[numElemHeaders] = serverTime;
            else
                elemHeaderData[numElemHeaders] = GetTimeInMillis();
            if (recordingClientSwapped)
                swapl(&elemHeaderData[numElemHeaders]);
            numElemHeaders++;
        }

        if ((pContext->elemHeaders & XRecordFromClientSequence)
            && (category == XRecordFromClient || category == XRecordClientDied)) {
            elemHeaderData[numElemHeaders] = pClient->sequence;
            if (recordingClientSwapped)
                swapl(&elemHeaderData[numElemHeaders]);
            numElemHeaders++;
        }

        /* adjust reply length */

        replylen = pRep->length;
        if (recordingClientSwapped)
            swapl(&replylen);
        replylen += numElemHeaders + bytes_to_int32(datalen) +
            bytes_to_int32(futurelen);
        if (recordingClientSwapped)
            swapl(&replylen);
        pRep->length = replylen;
    }                           /* end if not continued reply */

    numElemHeaders *= 4;

    /* if space available >= space needed, buffer the data */

    if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders) {
        if (numElemHeaders) {
            memcpy(pContext->replyBuffer + pContext->numBufBytes,
                   elemHeaderData, numElemHeaders);
            pContext->numBufBytes += numElemHeaders;
        }
        if (datalen) {
            static char padBuffer[3];   /* as in FlushClient */

            memcpy(pContext->replyBuffer + pContext->numBufBytes,
                   data, datalen - padlen);
            pContext->numBufBytes += datalen - padlen;
            memcpy(pContext->replyBuffer + pContext->numBufBytes,
                   padBuffer, padlen);
            pContext->numBufBytes += padlen;
        }
    }
    else {
        RecordFlushReplyBuffer(pContext, (void *) elemHeaderData,
                               numElemHeaders, (void *) data,
                               datalen - padlen);
    }
}                               /* RecordAProtocolElement */


RecordDeleteContext(void *value, XID id)
{
    int i;
    RecordContextPtr pContext = (RecordContextPtr) value;
    RecordClientsAndProtocolPtr pRCAP;

    RecordDisableContext(pContext);

    /*  Remove all the clients from all the RCAPs.
     *  As a result, the RCAPs will be freed.
     */

    while ((pRCAP = pContext->pListOfRCAP)) {
        int numClients = pRCAP->numClients;

        /* when the last client is deleted, the RCAP will go away. */
        while (numClients--) {
            RecordDeleteClientFromRCAP(pRCAP, numClients);
        }
    }

    /* remove context from AllContexts list */

    if (-1 != (i = RecordFindContextOnAllContexts(pContext))) {
        ppAllContexts[i] = ppAllContexts[numContexts - 1];
        if (--numContexts == 0) {
            free(ppAllContexts);
            ppAllContexts = NULL;
        }
    }
    free(pContext);

    return Success;
}                               /* RecordDeleteContext */


SProcRecordQueryVersion(ClientPtr client)
{
    REQUEST(xRecordQueryVersionReq);

    swaps(&stuff->length);
    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
    swaps(&stuff->majorVersion);
    swaps(&stuff->minorVersion);
    return ProcRecordQueryVersion(client);
}                               /* SProcRecordQueryVersion */


RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
{
    int i = 0;
    XID client;

    if (oneclient)
        client = oneclient;
    else
        client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;

    while (client) {
        if (client != XRecordFutureClients) {
            if (pRCAP->pRequestMajorOpSet) {
                ClientPtr pClient = clients[CLIENT_ID(client)];
                int c;
                Bool otherRCAPwantsProcVector = FALSE;
                RecordClientPrivatePtr pClientPriv = NULL;

                assert(pClient);
                pClientPriv = RecordClientPrivate(pClient);
                assert(pClientPriv);
                memcpy(pClientPriv->recordVector, pClientPriv->originalVector,
                       sizeof(pClientPriv->recordVector));

                for (c = 0; c < numEnabledContexts; c++) {
                    RecordClientsAndProtocolPtr pOtherRCAP;
                    RecordContextPtr pContext = ppAllContexts[c];

                    if (pContext == pRCAP->pContext)
                        continue;
                    pOtherRCAP = RecordFindClientOnContext(pContext, client,
                                                           NULL);
                    if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet) {
                        RecordSetIteratePtr pIter = NULL;
                        RecordSetInterval interval;

                        otherRCAPwantsProcVector = TRUE;
                        while ((pIter =
                                RecordIterateSet(pOtherRCAP->pRequestMajorOpSet,
                                                 pIter, &interval))) {
                            unsigned int j;

                            for (j = interval.first; j <= interval.last; j++)
                                pClient->requestVector[j] = RecordARequest;
                        }
                    }
                }
                if (!otherRCAPwantsProcVector) {        /* nobody needs it, so free it */
                    pClient->requestVector = pClientPriv->originalVector;
                    dixSetPrivate(&pClient->devPrivates,
                                  RecordClientPrivateKey, NULL);
                    free(pClientPriv);
                }
            }                   /* end if this RCAP specifies any requests */
        }                       /* end if not future clients */
        if (oneclient)
            client = 0;
        else
            client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
    }

    assert(numEnabledRCAPs >= 1);
    if (!oneclient && --numEnabledRCAPs == 0) { /* we're disabling the last context */
        DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL);
        DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL);
        DeleteCallback(&ReplyCallback, RecordAReply, NULL);
        DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL);
        /* Alternate context flushing scheme: delete the line above
         * and call RemoveBlockAndWakeupHandlers here passing
         * RecordFlushAllContexts.  Is this any better?
         */
        /* Having deleted the callback, call it one last time. -gildea */
        RecordFlushAllContexts(&FlushCallback, NULL, NULL);
    }
}                               /* RecordUninstallHooks */


ProcRecordGetContext(ClientPtr client)
{
    RecordContextPtr pContext;

    REQUEST(xRecordGetContextReq);
    xRecordGetContextReply rep;
    RecordClientsAndProtocolPtr pRCAP;
    int nRCAPs = 0;
    GetContextRangeInfoPtr pRangeInfo;
    GetContextRangeInfoPtr pri;
    int i;
    int err;
    CARD32 nClients, length;

    REQUEST_SIZE_MATCH(xRecordGetContextReq);
    VERIFY_CONTEXT(pContext, stuff->context, client);

    /* how many RCAPs are there on this context? */

    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
        nRCAPs++;

    /* allocate and initialize space for record range info */

    pRangeInfo = xallocarray(nRCAPs, sizeof(GetContextRangeInfoRec));
    if (!pRangeInfo && nRCAPs > 0)
        return BadAlloc;
    for (i = 0; i < nRCAPs; i++) {
        pRangeInfo[i].pRanges = NULL;
        pRangeInfo[i].size = 0;
        pRangeInfo[i].nRanges = 0;
    }

    /* convert the RCAP (internal) representation of the recorded protocol
     * to the wire protocol (external) representation, storing the information
     * for the ith RCAP in pri[i]
     */

    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
         pRCAP; pRCAP = pRCAP->pNextRCAP, pri++) {
        xRecordRange rr;

        err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri,
                                       offset_of(rr, coreRequestsFirst), TRUE,
                                       127, NULL);
        if (err != Success)
            goto bailout;

        err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri,
                                       offset_of(rr, coreRepliesFirst), TRUE,
                                       127, NULL);
        if (err != Success)
            goto bailout;

        err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri,
                                       offset_of(rr, deliveredEventsFirst),
                                       TRUE, 255, NULL);
        if (err != Success)
            goto bailout;

        err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri,
                                       offset_of(rr, deviceEventsFirst), TRUE,
                                       255, NULL);
        if (err != Success)
            goto bailout;

        err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri,
                                       offset_of(rr, errorsFirst), TRUE, 255,
                                       NULL);
        if (err != Success)
            goto bailout;

        err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo,
                                               pri, offset_of(rr,
                                                              extRequestsMajorFirst));
        if (err != Success)
            goto bailout;

        err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo,
                                               pri, offset_of(rr,
                                                              extRepliesMajorFirst));
        if (err != Success)
            goto bailout;

        if (pRCAP->clientStarted || pRCAP->clientDied) {
            if (pri->nRanges == 0)
                RecordAllocRanges(pri, 1);
            pri->pRanges[0].clientStarted = pRCAP->clientStarted;
            pri->pRanges[0].clientDied = pRCAP->clientDied;
        }
    }

    /* calculate number of clients and reply length */

    nClients = 0;
    length = 0;
    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
         pRCAP; pRCAP = pRCAP->pNextRCAP, pri++) {
        nClients += pRCAP->numClients;
        length += pRCAP->numClients *
            (bytes_to_int32(sizeof(xRecordClientInfo)) +
             pri->nRanges * bytes_to_int32(sizeof(xRecordRange)));
    }

    /* write the reply header */

    rep = (xRecordGetContextReply) {
        .type = X_Reply,
        .enabled = pContext->pRecordingClient != NULL,
        .sequenceNumber = client->sequence,
        .length = length,
        .elementHeader = pContext->elemHeaders,
        .nClients = nClients
    };
    if (client->swapped) {
        swaps(&rep.sequenceNumber);
        swapl(&rep.length);
        swapl(&rep.nClients);
    }
    WriteToClient(client, sizeof(xRecordGetContextReply), &rep);

    /* write all the CLIENT_INFOs */

    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
         pRCAP; pRCAP = pRCAP->pNextRCAP, pri++) {
        xRecordClientInfo rci;

        rci.nRanges = pri->nRanges;
        if (client->swapped) {
            swapl(&rci.nRanges);
            RecordSwapRanges(pri->pRanges, pri->nRanges);
        }
        for (i = 0; i < pRCAP->numClients; i++) {
            rci.clientResource = pRCAP->pClientIDs[i];
            if (client->swapped)
                swapl(&rci.clientResource);
            WriteToClient(client, sizeof(xRecordClientInfo), &rci);
            WriteToClient(client, sizeof(xRecordRange) * pri->nRanges,
                          pri->pRanges);
        }
    }
    err = Success;

 bailout:
    for (i = 0; i < nRCAPs; i++) {
        free(pRangeInfo[i].pRanges);
    }
    free(pRangeInfo);
    return err;
}                               /* ProcRecordGetContext */


dns_message_findname(dns_message_t *msg, dns_section_t section,
		     dns_name_t *target, dns_rdatatype_t type,
		     dns_rdatatype_t covers, dns_name_t **name,
		     dns_rdataset_t **rdataset)
{
	dns_name_t *foundname;
	isc_result_t result;

	/*
	 * XXX These requirements are probably too intensive, especially
	 * where things can be NULL, but as they are they ensure that if
	 * something is NON-NULL, indicating that the caller expects it
	 * to be filled in, that we can in fact fill it in.
	 */
	REQUIRE(msg != NULL);
	REQUIRE(VALID_SECTION(section));
	REQUIRE(target != NULL);
	REQUIRE(name == NULL || *name == NULL);

	if (type == dns_rdatatype_any) {
		REQUIRE(rdataset == NULL);
	} else {
		REQUIRE(rdataset == NULL || *rdataset == NULL);
	}

	result = findname(&foundname, target,
			  &msg->sections[section]);

	if (result == ISC_R_NOTFOUND)
		return (DNS_R_NXDOMAIN);
	else if (result != ISC_R_SUCCESS)
		return (result);

	if (name != NULL)
		*name = foundname;

	/*
	 * And now look for the type.
	 */
	if (ISC_UNLIKELY(type == dns_rdatatype_any))
		return (ISC_R_SUCCESS);

	result = dns_message_findtype(foundname, type, covers, rdataset);
	if (result == ISC_R_NOTFOUND)
		return (DNS_R_NXRRSET);

	return (result);
}


dns_message_destroy(dns_message_t **msgp) {
	dns_message_t *msg;

	REQUIRE(msgp != NULL);
	REQUIRE(DNS_MESSAGE_VALID(*msgp));

	msg = *msgp;
	*msgp = NULL;

	msgreset(msg, true);
	isc_mempool_destroy(&msg->namepool);
	isc_mempool_destroy(&msg->rdspool);
	msg->magic = 0;
	isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
}


msgblock_reset(dns_msgblock_t *block) {
	block->remaining = block->count;
}


render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
	int i;
	char addr[16], addr_text[64];
	uint16_t family;
	uint8_t addrlen, addrbytes, scopelen;
	isc_result_t result;

	/*
	 * Note: This routine needs to handle malformed ECS options.
	 */

	if (isc_buffer_remaininglength(ecsbuf) < 4)
		return (DNS_R_OPTERR);
	family = isc_buffer_getuint16(ecsbuf);
	addrlen = isc_buffer_getuint8(ecsbuf);
	scopelen = isc_buffer_getuint8(ecsbuf);

	addrbytes = (addrlen + 7) / 8;
	if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
		return (DNS_R_OPTERR);

	if (addrbytes > sizeof(addr))
		return (DNS_R_OPTERR);

	memset(addr, 0, sizeof(addr));
	for (i = 0; i < addrbytes; i ++)
		addr[i] = isc_buffer_getuint8(ecsbuf);

	switch (family) {
	case 0:
		if (addrlen != 0U || scopelen != 0U)
			return (DNS_R_OPTERR);
		strlcpy(addr_text, "0", sizeof(addr_text));
		break;
	case 1:
		if (addrlen > 32 || scopelen > 32)
			return (DNS_R_OPTERR);
		inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
		break;
	case 2:
		if (addrlen > 128 || scopelen > 128)
			return (DNS_R_OPTERR);
		inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
		break;
	default:
		return (DNS_R_OPTERR);
	}

	ADD_STRING(target, ": ");
	ADD_STRING(target, addr_text);
	snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
	ADD_STRING(target, addr_text);

	result = ISC_R_SUCCESS;

 cleanup:
	return (result);
}


dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
			isc_buffer_t *buffer)
{
	isc_region_t r;

	REQUIRE(DNS_MESSAGE_VALID(msg));
	REQUIRE(buffer != NULL);
	REQUIRE(msg->buffer == NULL);
	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);

	msg->cctx = cctx;

	/*
	 * Erase the contents of this buffer.
	 */
	isc_buffer_clear(buffer);

	/*
	 * Make certain there is enough for at least the header in this
	 * buffer.
	 */
	isc_buffer_availableregion(buffer, &r);
	if (r.length < DNS_MESSAGE_HEADERLEN)
		return (ISC_R_NOSPACE);

	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
		return (ISC_R_NOSPACE);

	/*
	 * Reserve enough space for the header in this buffer.
	 */
	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);

	msg->buffer = buffer;

	return (ISC_R_SUCCESS);
}


msgresetnames(dns_message_t *msg, unsigned int first_section) {
	unsigned int i;
	dns_name_t *name, *next_name;
	dns_rdataset_t *rds, *next_rds;

	/*
	 * Clean up name lists by calling the rdataset disassociate function.
	 */
	for (i = first_section; i < DNS_SECTION_MAX; i++) {
		name = ISC_LIST_HEAD(msg->sections[i]);
		while (name != NULL) {
			next_name = ISC_LIST_NEXT(name, link);
			ISC_LIST_UNLINK(msg->sections[i], name, link);

			rds = ISC_LIST_HEAD(name->list);
			while (rds != NULL) {
				next_rds = ISC_LIST_NEXT(rds, link);
				ISC_LIST_UNLINK(name->list, rds, link);

				INSIST(dns_rdataset_isassociated(rds));
				dns_rdataset_disassociate(rds);
				isc_mempool_put(msg->rdspool, rds);
				rds = next_rds;
			}
			if (dns_name_dynamic(name))
				dns_name_free(name, msg->mctx);
			isc_mempool_put(msg->namepool, name);
			name = next_name;
		}
	}
}


dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
	dns_message_resetsig(msg);
	return (dns_message_checksig(msg, view));
}


dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
	REQUIRE(DNS_MESSAGE_VALID(msg));
	REQUIRE(item != NULL && *item == NULL);

	*item = newoffsets(msg);
	if (*item == NULL)
		return (ISC_R_NOMEMORY);

	return (ISC_R_SUCCESS);
}