Catch input errors and exit early enough to print a reasonable diagnosis based on errno. Signed-off-by: Jonathan Nieder <jrnieder@xxxxxxxxx> --- Patches 1 and 2 first appeared in the svndiff0 series[1] (and that is the application I have in mind in sending them now). This patch #4 is just a demo. Untested, I'm afraid. I would be very interested in ideas for automatically testing it --- how to easily stimulate error paths? Good night, Jonathan [1] http://thread.gmane.org/gmane.comp.version-control.git/158731 vcs-svn/fast_export.c | 13 ++++++++++- vcs-svn/svndump.c | 53 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index 256a052..dc0ae4e 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -62,14 +62,23 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log, printf("progress Imported commit %d.\n\n", revision); } +static void die_short_read(void) +{ + if (buffer_ferror()) + die_errno("error reading dump file"); + die("invalid dump: unexpected end of file"); +} + void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len) { if (mode == REPO_MODE_LNK) { /* svn symlink blobs start with "link " */ - buffer_skip_bytes(5); len -= 5; + if (buffer_skip_bytes(5) != 5) + die_short_read(); } printf("blob\nmark :%d\ndata %d\n", mark, len); - buffer_copy_bytes(len); + if (buffer_copy_bytes(len) != len) + die_short_read(); fputc('\n', stdout); } diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index 630eeb5..09bcebd 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -107,20 +107,37 @@ static void init_keys(void) keys.content_length = pool_intern("Content-length"); } +static void die_short_read(void) +{ + if (buffer_ferror()) + die_errno("error reading dump file"); + die("invalid dump: unexpected end of file"); +} + static void read_props(void) { uint32_t len; uint32_t key = ~0; char *val = NULL; - char *t; - while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) { + for (;;) { + char *t = buffer_read_line(); + if (!t) + die_short_read(); + if (!strcmp(t, "PROPS-END")) + return; if (!strncmp(t, "K ", 2)) { len = atoi(&t[2]); - key = pool_intern(buffer_read_string(len)); - buffer_read_line(); + t = buffer_read_line(); + if (!t) + die_short_read(); + if (strlen(t) != len) + die("invalid dump: incorrect key length"); + key = pool_intern(t); } else if (!strncmp(t, "V ", 2)) { len = atoi(&t[2]); val = buffer_read_string(len); + if (!t) + die_short_read(); if (key == keys.svn_log) { /* Value length excludes terminating nul. */ rev_ctx.log = log_copy(len + 1, val); @@ -135,7 +152,11 @@ static void read_props(void) node_ctx.type = REPO_MODE_LNK; } key = ~0; - buffer_read_line(); + t = buffer_read_line(); + if (!t) + die_short_read(); + if (*t) + die("invalid dump: incorrect value length"); } } } @@ -176,10 +197,12 @@ static void handle_node(void) if (node_ctx.propLength == LENGTH_UNKNOWN && node_ctx.srcMode) node_ctx.type = node_ctx.srcMode; - if (node_ctx.mark) + if (node_ctx.mark) { fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength); - else if (node_ctx.textLength != LENGTH_UNKNOWN) - buffer_skip_bytes(node_ctx.textLength); + } else if (node_ctx.textLength != LENGTH_UNKNOWN) { + if (buffer_skip_bytes(node_ctx.textLength) != node_ctx.textLength) + die_short_read(); + } } static void handle_revision(void) @@ -250,7 +273,11 @@ void svndump_read(const char *url) node_ctx.propLength = atoi(val); } else if (key == keys.content_length) { len = atoi(val); - buffer_read_line(); + t = buffer_read_line(); + if (!t) + die_short_read(); + if (*t) + die("invalid dump: expected blank line after content length header"); if (active_ctx == REV_CTX) { read_props(); } else if (active_ctx == NODE_CTX) { @@ -258,10 +285,13 @@ void svndump_read(const char *url) active_ctx = REV_CTX; } else { fprintf(stderr, "Unexpected content length header: %d\n", len); - buffer_skip_bytes(len); + if (buffer_skip_bytes(len) != len) + die_short_read(); } } } + if (buffer_ferror()) + die_short_read(); if (active_ctx == NODE_CTX) handle_node(); if (active_ctx != DUMP_CTX) @@ -270,7 +300,8 @@ void svndump_read(const char *url) void svndump_init(const char *filename) { - buffer_init(filename); + if (buffer_init(filename)) + die_errno("cannot open dump file: %s", filename); repo_init(); reset_dump_ctx(~0); reset_rev_ctx(0); -- 1.7.2.3.554.gc9b5c.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html