[PATCH 4/4] vcs-svn: improve reporting of input errors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]