Handle short writes gracefully.
[ruby-vorbistagger.git] / ext / vcedit.c
index 795b0c3e1011510a60f18aa2eed53ef694c1b3db..b9650f8a157ed395281fece20874a1c24165b9df 100644 (file)
@@ -240,7 +240,7 @@ _fetch_next_packet (vcedit_state *s, ogg_packet *p, ogg_page *page)
                bytes = fread (buffer, 1, CHUNKSIZE, s->in);
                ogg_sync_wrote (&s->oy, bytes);
 
-               if (!bytes)
+               if (!bytes && feof (s->in))
                        return 0;
        }
 
@@ -355,7 +355,7 @@ vcedit_open (vcedit_state *state)
                buffer = ogg_sync_buffer (&state->oy, CHUNKSIZE);
                bytes = fread (buffer, 1, CHUNKSIZE, state->in);
 
-               if (!bytes && i < 2) {
+               if (!bytes && feof (state->in) && i < 2) {
                        ret = VCEDIT_ERR_INVAL;
                        goto err;
                }
@@ -377,6 +377,23 @@ err:
        return ret;
 }
 
+static int
+write_data (const void *buf, size_t size, size_t nmemb, FILE *stream)
+{
+       while (nmemb > 0) {
+               size_t w;
+
+               w = fwrite (buf, size, nmemb, stream);
+               if (!w && ferror (stream))
+                       return 0;
+
+               nmemb -= w;
+               buf += size * w;
+       }
+
+       return 1;
+}
+
 vcedit_error
 vcedit_write (vcedit_state *state)
 {
@@ -387,7 +404,6 @@ vcedit_write (vcedit_state *state)
        FILE *out;
        char *buffer, tmpfile[PATH_MAX];
        int s, result, bytes, needflush = 0, needout = 0;
-       size_t tmp;
 
        if (!state->opened)
                return VCEDIT_ERR_INVAL;
@@ -430,12 +446,10 @@ vcedit_write (vcedit_state *state)
        ogg_stream_packetin (&streamout, &header_codebooks);
 
        while ((result = ogg_stream_flush (&streamout, &ogout))) {
-               tmp = fwrite (ogout.header, 1, ogout.header_len, out);
-               if (tmp != (size_t) ogout.header_len)
+               if (!write_data (ogout.header, 1, ogout.header_len, out))
                        goto cleanup;
 
-               tmp = fwrite (ogout.body, 1, ogout.body_len, out);
-               if (tmp != (size_t) ogout.body_len)
+               if (!write_data (ogout.body, 1, ogout.body_len, out))
                        goto cleanup;
        }
 
@@ -447,22 +461,18 @@ vcedit_write (vcedit_state *state)
 
                if (needflush) {
                        if (ogg_stream_flush (&streamout, &ogout)) {
-                               tmp = fwrite (ogout.header, 1, ogout.header_len, out);
-                               if (tmp != (size_t) ogout.header_len)
+                               if (!write_data (ogout.header, 1, ogout.header_len, out))
                                        goto cleanup;
 
-                               tmp = fwrite (ogout.body, 1, ogout.body_len, out);
-                               if (tmp != (size_t) ogout.body_len)
+                               if (!write_data (ogout.body, 1, ogout.body_len, out))
                                        goto cleanup;
                        }
                } else if (needout) {
                        if (ogg_stream_pageout (&streamout, &ogout)) {
-                               tmp = fwrite (ogout.header, 1, ogout.header_len, out);
-                               if (tmp != (size_t) ogout.header_len)
+                               if (!write_data (ogout.header, 1, ogout.header_len, out))
                                        goto cleanup;
 
-                               tmp = fwrite (ogout.body, 1, ogout.body_len, out);
-                               if (tmp != (size_t) ogout.body_len)
+                               if (!write_data (ogout.body, 1, ogout.body_len, out))
                                        goto cleanup;
                        }
                }
@@ -490,29 +500,25 @@ vcedit_write (vcedit_state *state)
        streamout.e_o_s = 1;
 
        while (ogg_stream_flush (&streamout, &ogout)) {
-               tmp = fwrite (ogout.header, 1, ogout.header_len, out);
-               if (tmp != (size_t) ogout.header_len)
+               if (!write_data (ogout.header, 1, ogout.header_len, out))
                        goto cleanup;
 
-               tmp = fwrite (ogout.body, 1, ogout.body_len, out);
-               if (tmp != (size_t) ogout.body_len)
+               if (!write_data (ogout.body, 1, ogout.body_len, out))
                        goto cleanup;
        }
 
        if (state->extrapage) {
-               tmp = fwrite (ogin.header, 1, ogin.header_len, out);
-               if (tmp != (size_t) ogin.header_len)
+               if (!write_data (ogin.header, 1, ogin.header_len, out))
                        goto cleanup;
 
-               tmp = fwrite (ogin.body, 1, ogin.body_len, out);
-               if (tmp != (size_t) ogin.body_len)
+               if (!write_data (ogin.body, 1, ogin.body_len, out))
                        goto cleanup;
        }
 
        /* clear it, because not all paths to here do */
        state->eosin = 0;
 
-       while (!state->eosin) { /* We reached eos, not eof */
+       do {
                /* We copy the rest of the stream (other logical streams)
                 * through, a page at a time.
                 */
@@ -523,12 +529,10 @@ vcedit_write (vcedit_state *state)
                        /* Don't bother going through the rest, we can just
                         * write the page out now
                         */
-                       tmp = fwrite (ogout.header, 1, ogout.header_len, out);
-                       if (tmp != (size_t) ogout.header_len)
+                       if (!write_data (ogout.header, 1, ogout.header_len, out))
                                goto cleanup;
 
-                       tmp = fwrite (ogout.body, 1, ogout.body_len, out);
-                       if (tmp != (size_t) ogout.body_len)
+                       if (!write_data (ogout.body, 1, ogout.body_len, out))
                                goto cleanup;
                }
 
@@ -536,9 +540,8 @@ vcedit_write (vcedit_state *state)
                bytes = fread (buffer, 1, CHUNKSIZE, state->in);
                ogg_sync_wrote (&state->oy, bytes);
 
-               if (!bytes)
-                       state->eosin = 1;
-       }
+               state->eosin = !bytes && feof (state->in);
+       } while (!state->eosin);
 
        fclose (out);
        fclose (state->in);