improve stream read and write error handling - stagit - static git page generator
 (HTM) git clone git://git.codemadness.org/stagit
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit d0e36eb6abce72c587dd53dcabc35120c3cf3a81
 (DIR) parent 7c419a8bac26e491206953bf2646ac634296b160
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sat, 19 Mar 2022 12:22:43 +0100
       
       improve stream read and write error handling
       
       Diffstat:
         M stagit-index.c                      |      16 +++++++++++++++-
         M stagit.c                            |      35 ++++++++++++++++++++++++-------
       
       2 files changed, 42 insertions(+), 9 deletions(-)
       ---
 (DIR) diff --git a/stagit-index.c b/stagit-index.c
       @@ -16,6 +16,16 @@ static char description[255] = "Repositories";
        static char *name = "";
        static char owner[255];
        
       +/* Handle read or write errors for a FILE * stream */
       +void
       +checkfileerror(FILE *fp, const char *name, int mode)
       +{
       +        if (mode == 'r' && ferror(fp))
       +                errx(1, "read error: %s", name);
       +        else if (mode == 'w' && (fflush(fp) || ferror(fp)))
       +                errx(1, "write error: %s", name);
       +}
       +
        void
        joinpath(char *buf, size_t bufsiz, const char *path, const char *path2)
        {
       @@ -214,6 +224,7 @@ main(int argc, char *argv[])
                        if (fp) {
                                if (!fgets(description, sizeof(description), fp))
                                        description[0] = '\0';
       +                        checkfileerror(fp, "description", 'r');
                                fclose(fp);
                        }
        
       @@ -227,8 +238,9 @@ main(int argc, char *argv[])
                        if (fp) {
                                if (!fgets(owner, sizeof(owner), fp))
                                        owner[0] = '\0';
       -                        owner[strcspn(owner, "\n")] = '\0';
       +                        checkfileerror(fp, "owner", 'r');
                                fclose(fp);
       +                        owner[strcspn(owner, "\n")] = '\0';
                        }
                        writelog(stdout);
                }
       @@ -238,5 +250,7 @@ main(int argc, char *argv[])
                git_repository_free(repo);
                git_libgit2_shutdown();
        
       +        checkfileerror(stdout, "<stdout>", 'w');
       +
                return ret;
        }
 (DIR) diff --git a/stagit.c b/stagit.c
       @@ -79,6 +79,16 @@ static char lastoidstr[GIT_OID_HEXSZ + 2]; /* id + newline + NUL byte */
        static FILE *rcachefp, *wcachefp;
        static const char *cachefile;
        
       +/* Handle read or write errors for a FILE * stream */
       +void
       +checkfileerror(FILE *fp, const char *name, int mode)
       +{
       +        if (mode == 'r' && ferror(fp))
       +                errx(1, "read error: %s", name);
       +        else if (mode == 'w' && (fflush(fp) || ferror(fp)))
       +                errx(1, "write error: %s", name);
       +}
       +
        void
        joinpath(char *buf, size_t bufsiz, const char *path, const char *path2)
        {
       @@ -814,6 +824,7 @@ writelog(FILE *fp, const git_oid *oid)
                                printshowfile(fpfile, ci);
                                fputs("</pre>\n", fpfile);
                                writefooter(fpfile);
       +                        checkfileerror(fpfile, path, 'w');
                                fclose(fpfile);
                        }
        err:
       @@ -963,14 +974,13 @@ writeblob(git_object *obj, const char *fpath, const char *filename, size_t files
                fprintf(fp, " (%zuB)", filesize);
                fputs("</p><hr/>", fp);
        
       -        if (git_blob_is_binary((git_blob *)obj)) {
       +        if (git_blob_is_binary((git_blob *)obj))
                        fputs("<p>Binary file.</p>\n", fp);
       -        } else {
       +        else
                        lc = writeblobhtml(fp, (git_blob *)obj);
       -                if (ferror(fp))
       -                        err(1, "fwrite");
       -        }
       +
                writefooter(fp);
       +        checkfileerror(fp, fpath, 'w');
                fclose(fp);
        
                relpath = "";
       @@ -1276,6 +1286,7 @@ main(int argc, char *argv[])
                if (fpread) {
                        if (!fgets(description, sizeof(description), fpread))
                                description[0] = '\0';
       +                checkfileerror(fpread, path, 'r');
                        fclose(fpread);
                }
        
       @@ -1288,8 +1299,9 @@ main(int argc, char *argv[])
                if (fpread) {
                        if (!fgets(cloneurl, sizeof(cloneurl), fpread))
                                cloneurl[0] = '\0';
       -                cloneurl[strcspn(cloneurl, "\n")] = '\0';
       +                checkfileerror(fpread, path, 'r');
                        fclose(fpread);
       +                cloneurl[strcspn(cloneurl, "\n")] = '\0';
                }
        
                /* check LICENSE */
       @@ -1349,13 +1361,15 @@ main(int argc, char *argv[])
                                while (!feof(rcachefp)) {
                                        n = fread(buf, 1, sizeof(buf), rcachefp);
                                        if (ferror(rcachefp))
       -                                        err(1, "fread");
       +                                        break;
                                        if (fwrite(buf, 1, n, fp) != n ||
                                            fwrite(buf, 1, n, wcachefp) != n)
       -                                        err(1, "fwrite");
       +                                            break;
                                }
       +                        checkfileerror(rcachefp, cachefile, 'r');
                                fclose(rcachefp);
                        }
       +                checkfileerror(wcachefp, tmppath, 'w');
                        fclose(wcachefp);
                } else {
                        if (head)
       @@ -1364,6 +1378,7 @@ main(int argc, char *argv[])
        
                fputs("</tbody></table>", fp);
                writefooter(fp);
       +        checkfileerror(fp, "log.html", 'w');
                fclose(fp);
        
                /* files for HEAD */
       @@ -1372,6 +1387,7 @@ main(int argc, char *argv[])
                if (head)
                        writefiles(fp, head);
                writefooter(fp);
       +        checkfileerror(fp, "files.html", 'w');
                fclose(fp);
        
                /* summary page with branches and tags */
       @@ -1379,16 +1395,19 @@ main(int argc, char *argv[])
                writeheader(fp, "Refs");
                writerefs(fp);
                writefooter(fp);
       +        checkfileerror(fp, "refs.html", 'w');
                fclose(fp);
        
                /* Atom feed */
                fp = efopen("atom.xml", "w");
                writeatom(fp, 1);
       +        checkfileerror(fp, "atom.xml", 'w');
                fclose(fp);
        
                /* Atom feed for tags / releases */
                fp = efopen("tags.xml", "w");
                writeatom(fp, 0);
       +        checkfileerror(fp, "tags.xml", 'w');
                fclose(fp);
        
                /* rename new cache file on success */