diff options
-rw-r--r-- | source3/include/proto.h | 4 | ||||
-rw-r--r-- | source3/lib/charcnv.c | 89 |
2 files changed, 75 insertions, 18 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index e797b14b16..737dbec931 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -416,6 +416,10 @@ void init_iconv(void); size_t convert_string(charset_t from, charset_t to, void const *src, size_t srclen, void *dest, size_t destlen); +size_t convert_string_error(charset_t from, charset_t to, + void const *src, size_t srclen, + void *dest, size_t destlen, + size_t *converted_size); size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen); char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *s); char *strupper_talloc(TALLOC_CTX *ctx, const char *s); diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c index cf6dbdd95a..77d36dbdfd 100644 --- a/source3/lib/charcnv.c +++ b/source3/lib/charcnv.c @@ -96,7 +96,7 @@ void init_iconv(void) static size_t convert_string_internal(charset_t from, charset_t to, void const *src, size_t srclen, - void *dest, size_t destlen) + void *dest, size_t destlen, size_t *converted_size) { size_t i_len, o_len; size_t retval; @@ -181,9 +181,10 @@ static size_t convert_string_internal(charset_t from, charset_t to, * Don't change unless you really know what you are doing. JRA. **/ -size_t convert_string(charset_t from, charset_t to, - void const *src, size_t srclen, - void *dest, size_t destlen) +size_t convert_string_error(charset_t from, charset_t to, + void const *src, size_t srclen, + void *dest, size_t destlen, + size_t *converted_size) { /* * NB. We deliberately don't do a strlen here if srclen == -1. @@ -195,6 +196,10 @@ size_t convert_string(charset_t from, charset_t to, SMB_ASSERT(destlen != (size_t)-1); #endif + if (converted_size) { + *converted_size = 0; + } + if (srclen == 0) return 0; @@ -221,11 +226,11 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - size_t ret = convert_string_internal(from, to, p, slen, q, dlen); - if (ret == (size_t)-1) { - return ret; + size_t ret = convert_string_internal(from, to, p, slen, q, dlen, converted_size); + if (converted_size) { + *converted_size += retval; } - return retval + ret; + return ret; #endif } } @@ -261,11 +266,11 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - size_t ret = convert_string_internal(from, to, p, slen, q, dlen); - if (ret == (size_t)-1) { - return ret; + size_t ret = convert_string_internal(from, to, p, slen, q, dlen, converted_size); + if (converted_size) { + *converted_size += retval; } - return retval + ret; + return ret; #endif } } @@ -301,30 +306,78 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - size_t ret = convert_string_internal(from, to, p, slen, q, dlen); - if (ret == (size_t)-1) { - return ret; + size_t ret = convert_string_internal(from, to, p, slen, q, dlen, converted_size); + if (converted_size) { + *converted_size += retval; } - return retval + ret; + return ret; #endif } } + if (converted_size) { + *converted_size += retval; + } if (!dlen) { /* Even if we fast path we should note if we ran out of room. */ if (((slen != (size_t)-1) && slen) || ((slen == (size_t)-1) && lastp)) { errno = E2BIG; + return -1; } } - return retval; + return 0; } #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS general_case: #endif - return convert_string_internal(from, to, src, srclen, dest, destlen); + return convert_string_internal(from, to, src, srclen, dest, destlen, converted_size); +} + +size_t convert_string(charset_t from, charset_t to, + void const *src, size_t srclen, + void *dest, size_t destlen) { + size_t converted_size; + size_t retval = convert_string_error(from, to, src, srclen, dest, destlen, &converted_size); + if(retval==(size_t)-1) { + const char *reason="unknown error"; + switch(errno) { + case EINVAL: + reason="Incomplete multibyte sequence"; + DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,src)); + return (size_t)-1; + case E2BIG: + { + struct smb_iconv_handle *ic; + lazy_initialize_conv(); + ic = get_iconv_handle(); + + reason="No more room"; + if (from == CH_UNIX) { + DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n", + charset_name(ic, from), charset_name(ic, to), + (unsigned int)srclen, (unsigned int)destlen, (const char *)src)); + } else { + DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n", + charset_name(ic, from), charset_name(ic, to), + (unsigned int)srclen, (unsigned int)destlen)); + } + break; + } + case EILSEQ: + reason="Illegal multibyte sequence"; + DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,src)); + return (size_t)-1; + default: + DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,src)); + return (size_t)-1; + } + /* smb_panic(reason); */ + } + return converted_size; } + /** * Convert between character sets, allocating a new buffer using talloc for the result. * |