示例#1
0
文件: rsync.c 项目: inteos/WBSAirback
/* This function converts the characters in the "in" xbuf into characters
 * in the "out" xbuf.  The "len" of the "in" xbuf is used starting from its
 * "pos".  The "size" of the "out" xbuf restricts how many characters can be
 * stored, starting at its "pos+len" position.  Note that the last byte of
 * the buffer is never used, which reserves space for a terminating '\0'.
 * We return a 0 on success or a -1 on error.  An error also sets errno to
 * E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0.
 * The "in" xbuf is altered to update "pos" and "len".  The "out" xbuf has
 * data appended, and its "len" incremented.   If ICB_EXPAND_OUT is set in
 * "flags", the "out" xbuf will also be allocated if empty, and expanded if
 * too small (so E2BIG will not be returned).  If ICB_INCLUDE_BAD is set in
 * "flags", any badly-encoded chars are included verbatim in the "out" xbuf,
 * so EILSEQ will not be returned.  Likewise for ICB_INCLUDE_INCOMPLETE with
 * respect to an incomplete multi-byte char at the end, which ensures that
 * EINVAL is not returned.  Anytime "in.pos" is 0 we will reset the iconv()
 * state prior to processing the characters. */
int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
{
	ICONV_CONST char *ibuf;
	size_t icnt, ocnt;
	char *obuf;

	if (!out->size && flags & ICB_EXPAND_OUT)
		alloc_xbuf(out, 1024);

	if (!in->pos)
		iconv(ic, NULL, 0, NULL, 0);

	ibuf = in->buf + in->pos;
	icnt = in->len;

	obuf = out->buf + (out->pos + out->len);
	ocnt = out->size - (out->pos + out->len) - 1;

	while (icnt) {
		while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) {
			if (errno == EINTR)
				continue;
			if (errno == EINVAL) {
				if (!(flags & ICB_INCLUDE_INCOMPLETE))
					goto finish;
			} else if (errno == EILSEQ) {
				if (!(flags & ICB_INCLUDE_BAD))
					goto finish;
			} else {
				size_t opos = obuf - out->buf;
				if (!(flags & ICB_EXPAND_OUT)) {
					errno = E2BIG;
					goto finish;
				}
				realloc_xbuf(out, out->size + 1024);
				obuf = out->buf + opos;
				ocnt += 1024;
				continue;
			}
			*obuf++ = *ibuf++;
			ocnt--, icnt--;
		}
	}

	errno = 0;

  finish:
	in->len = icnt;
	in->pos = ibuf - in->buf;
	out->len = obuf - out->buf - out->pos;

	return errno ? -1 : 0;
}
示例#2
0
文件: rsync.c 项目: ain-ver/rsync
/* This function converts the chars in the "in" xbuf into characters in the
 * "out" xbuf.  The ".len" chars of the "in" xbuf is used starting from its
 * ".pos".  The ".size" of the "out" xbuf restricts how many characters can
 * be stored, starting at its ".pos+.len" position.  Note that the last byte
 * of the "out" xbuf is not used, which reserves space for a trailing '\0'
 * (though it is up to the caller to store a trailing '\0', as needed).
 *
 * We return a 0 on success or a -1 on error.  An error also sets errno to
 * E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0.
 * The "in" xbuf is altered to update ".pos" and ".len".  The "out" xbuf has
 * data appended, and its ".len" incremented (see below for a ".size" note).
 *
 * If ICB_CIRCULAR_OUT is set in "flags", the chars going into the "out" xbuf
 * can wrap around to the start, and the xbuf may have its ".size" reduced
 * (presumably by 1 byte) if the iconv code doesn't have space to store a
 * multi-byte character at the physical end of the ".buf" (though no reducing
 * happens if ".pos" is <= 1, since there is no room to wrap around).
 *
 * If ICB_EXPAND_OUT is set in "flags", the "out" xbuf will be allocated if
 * empty, and (as long as ICB_CIRCULAR_OUT is not set) expanded if too small.
 * This prevents the return of E2BIG (except for a circular xbuf).
 *
 * If ICB_INCLUDE_BAD is set in "flags", any badly-encoded chars are included
 * verbatim in the "out" xbuf, so EILSEQ will not be returned.
 *
 * If ICB_INCLUDE_INCOMPLETE is set in "flags", any incomplete multi-byte
 * chars are included, which ensures that EINVAL is not returned.
 *
 * If ICB_INIT is set, the iconv() conversion state is initialized prior to
 * processing the characters. */
int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
{
	ICONV_CONST char *ibuf;
	size_t icnt, ocnt, opos;
	char *obuf;

	if (!out->size && flags & ICB_EXPAND_OUT) {
		size_t siz = ROUND_UP_1024(in->len * 2);
		alloc_xbuf(out, siz);
	} else if (out->len+1 >= out->size) {
		/* There is no room to even start storing data. */
		if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) {
			errno = E2BIG;
			return -1;
		}
		realloc_xbuf(out, out->size + ROUND_UP_1024(in->len * 2));
	}

	if (flags & ICB_INIT)
		iconv(ic, NULL, 0, NULL, 0);

	ibuf = in->buf + in->pos;
	icnt = in->len;

	opos = out->pos + out->len;
	if (flags & ICB_CIRCULAR_OUT) {
		if (opos >= out->size) {
			opos -= out->size;
			/* We know that out->pos is not 0 due to the "no room" check
			 * above, so this can't go "negative". */
			ocnt = out->pos - opos - 1;
		} else {
			/* Allow the use of all bytes to the physical end of the buffer
			 * unless pos is 0, in which case we reserve our trailing '\0'. */
			ocnt = out->size - opos - (out->pos ? 0 : 1);
		}
	} else
		ocnt = out->size - opos - 1;
	obuf = out->buf + opos;

	while (icnt) {
		while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) {
			if (errno == EINTR)
				continue;
			if (errno == EINVAL) {
				if (!(flags & ICB_INCLUDE_INCOMPLETE))
					goto finish;
			} else if (errno == EILSEQ) {
				if (!(flags & ICB_INCLUDE_BAD))
					goto finish;
			} else if (errno == E2BIG) {
				size_t siz;
				opos = obuf - out->buf;
				if (flags & ICB_CIRCULAR_OUT && out->pos > 1 && opos > out->pos) {
					/* We are in a divided circular buffer at the physical
					 * end with room to wrap to the start.  If iconv() refused
					 * to use one or more trailing bytes in the buffer, we
					 * set the size to ignore the unused bytes. */
					if (opos < out->size)
						reduce_iobuf_size(out, opos);
					obuf = out->buf;
					ocnt = out->pos - 1;
					continue;
				}
				if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) {
					errno = E2BIG;
					goto finish;
				}
				siz = ROUND_UP_1024(in->len * 2);
				realloc_xbuf(out, out->size + siz);
				obuf = out->buf + opos;
				ocnt += siz;
				continue;
			} else {
				rsyserr(FERROR, errno, "unexpected error from iconv()");
				exit_cleanup(RERR_UNSUPPORTED);
			}
			*obuf++ = *ibuf++;
			ocnt--, icnt--;
		}
	}

	errno = 0;

  finish:
	opos = obuf - out->buf;
	if (flags & ICB_CIRCULAR_OUT && opos < out->pos)
		opos += out->size;
	out->len = opos - out->pos;

	in->len = icnt;
	in->pos = ibuf - in->buf;

	return errno ? -1 : 0;
}