TMP try to fix smb_iconv to report the correct inbytesleft when push fails
authorMichael Adam <obnox@samba.org>
Wed, 25 Aug 2010 08:39:13 +0000 (10:39 +0200)
committerMichael Adam <obnox@samba.org>
Thu, 26 Aug 2010 11:51:16 +0000 (13:51 +0200)
lib/util/charset/iconv.c

index 2dac333d0c4beed9b199f212fe50c788c41ce385..0458c5f67abc4f0d535a2b9f6d4f45eb9eceb5eb 100644 (file)
@@ -123,6 +123,7 @@ _PUBLIC_ size_t smb_iconv(smb_iconv_t cd,
 {
        char cvtbuf[2048];
        size_t bufsize;
+       size_t ret;
 
        /* in many cases we can go direct */
        if (cd->direct) {
@@ -135,18 +136,58 @@ _PUBLIC_ size_t smb_iconv(smb_iconv_t cd,
        while (*inbytesleft > 0) {
                char *bufp1 = cvtbuf;
                const char *bufp2 = cvtbuf;
+               size_t inbytesleft_tmp;
+               const char *inbuf_tmp;
 
+               inbuf_tmp = *inbuf;
+               inbytesleft_tmp = *inbytesleft;
                bufsize = sizeof(cvtbuf);
                
                if (cd->pull(cd->cd_pull, 
-                            inbuf, inbytesleft, &bufp1, &bufsize) == -1
+                            &inbuf_tmp, &inbytesleft_tmp, &bufp1, &bufsize) == -1
                    && errno != E2BIG) return -1;
 
                bufsize = sizeof(cvtbuf) - bufsize;
 
                if (cd->push(cd->cd_push, 
                             &bufp2, &bufsize, 
-                            outbuf, outbytesleft) == -1) return -1;
+                            outbuf, outbytesleft) == -1)
+               {
+                       if (errno != E2BIG) {
+                               return -1;
+                       }
+
+                       /*
+                        * push returned E2BIG:
+                        * re-run the pull operation with adapted
+                        * bufsize to get the correct inbytesleft count
+                        */
+
+                       inbuf_tmp = *inbuf;
+                       inbytesleft_tmp = *inbytesleft;
+                       bufsize = sizeof(cvtbuf) - bufsize;
+
+                       ret = cd->pull(cd->cd_pull,
+                                      &inbuf_tmp, &inbytesleft_tmp,
+                                      &bufp1, &bufsize);
+
+                       if (ret != -1 || errno != E2BIG) {
+                               DEBUG(0, ("Interal error: expected E2BIG from "
+                                         "pull, when retrying pull to get "
+                                         "proper inbytesleft. Don't know what "
+                                         "to do.\n"));
+                               errno = EFAULT;
+                               return -1;
+                       }
+
+                       *inbytesleft = inbytesleft_tmp;
+                       *inbuf = inbuf_tmp;
+
+                       return -1;
+               }
+
+               *inbytesleft = inbytesleft_tmp;
+               *inbuf = inbuf_tmp;
        }
 
        return 0;