Julian Foad wrote:
>
> When the dump stream being read by 'svnadmin load' ends prematurely, in
> several cases no error is detected.
[...]
> head -c $SIZE dump1 |
> svnadmin load repos2 2>&1 >/dev/null &&
> svnadmin verify repos2
[...]
>> Trying to load the first 200 bytes...
>> * Verified revision 0.
The dump stream format is not designed for being able to detect all
modifications, so if it happens to be cut off accidentally at a clean break,
such as between one node or revision and the next, this will never be detected
as an error. Here's a snippet:
> Revision-number: 5
(EOF here is not detected; I expect it could be.)
> Prop-content-length: 116
> Content-length: 116
>
> K 7
> svn:log
> V 10
> Check in 2
> K 10
> svn:author
> V 10
> julianfoad
> K 8
> svn:date
> V 27
> 2003-07-18T21:56:02.803550Z
> PROPS-END
>
(EOF here is not detected, and can't be, I think.)
> Node-path: one
> Node-kind: file
> Node-action: add
(EOF here not detected; difficult, as following are not always required.)
> Prop-content-length: 10
> Text-content-length: 4
> Text-content-md5: 5bbf5a52328e7439ae6e719dfe712200
> Content-length: 14
>
> PROPS-END
> one
>
The attached patch adds missing checks for premature EOF. Does it look sane?
EOF part-way through a line is now detected, and it thereby catches and errors
out on a much higher proportion of arbitrarily cut-off dump streams (like maybe
98% compared to 80%).
My concern was that accidental truncation would be missed. That case is fairly
well addressed by this patch. There's not much more to gain by trying to catch
some of the remaining EOF cases.
*Special attention* At the end of the patch I make sure that missing
node-action and copyfrom-rev headers don't assume a valid value. Is that safe?
- Julian
Make "svnadmin load" more robust in detecting a broken dump file, especially
one that is cut off.
* subversion/libsvn_repos/load.c
(stream_ran_dry, stream_malformed): Move these functions nearer to the
start of the file so we can call them.
(read_header_block, parse_property_block, svn_repos_parse_dumpstream2):
Check for premature EOF.
(make_node_baton): Initialise fields to invalid values so that missing
headers will be detected.
Index: subversion/libsvn_repos/load.c
===================================================================
--- subversion/libsvn_repos/load.c (revision 18347)
+++ subversion/libsvn_repos/load.c (working copy)
@@ -110,6 +110,20 @@ fns2_from_fns (const svn_repos_parser_fn
/** The parser and related helper funcs **/
+static svn_error_t *
+stream_ran_dry (void)
+{
+ return svn_error_create (SVN_ERR_INCOMPLETE_DATA, NULL,
+ _("Premature end of content data in dumpstream"));
+}
+
+static svn_error_t *
+stream_malformed (void)
+{
+ return svn_error_create (SVN_ERR_STREAM_MALFORMED_DATA, NULL,
+ _("Dumpstream data appears to be malformed"));
+}
+
/* Allocate a new hash *HEADERS in POOL, and read a series of
RFC822-style headers from STREAM. Duplicate each header's name and
value into POOL and store in hash as a const char * ==> const char *.
@@ -145,9 +159,11 @@ read_header_block (svn_stream_t *stream,
else
/* Read the next line into a stringbuf. */
SVN_ERR (svn_stream_readline (stream, &header_str, "\n", &eof, pool));
-
- if (eof || svn_stringbuf_isempty(header_str))
+
+ if (svn_stringbuf_isempty(header_str))
break; /* end of header block */
+ else if (eof)
+ return stream_ran_dry ();
/* Find the next colon in the stringbuf. */
while (header_str->data[i] != ':')
@@ -182,20 +198,6 @@ read_header_block (svn_stream_t *stream,
}
-static svn_error_t *
-stream_ran_dry (void)
-{
- return svn_error_create (SVN_ERR_INCOMPLETE_DATA, NULL,
- _("Premature end of content data in dumpstream"));
-}
-
-static svn_error_t *
-stream_malformed (void)
-{
- return svn_error_create (SVN_ERR_STREAM_MALFORMED_DATA, NULL,
- _("Dumpstream data appears to be malformed"));
-}
-
/* Set *PBUF to a string of length LEN, allocated in POOL, read from STREAM.
Also read a newline from STREAM and increase *ACTUAL_LEN by the total
number of bytes read from STREAM. */
@@ -283,6 +285,9 @@ parse_property_block (svn_stream_t *stre
/* Read a val length line */
SVN_ERR (svn_stream_readline (stream, &strbuf, "\n", &eof, pool));
+ if (eof)
+ return stream_ran_dry ();
+
*actual_length += (strbuf->len + 1); /* +1 because we read \n too */
buf = strbuf->data;
@@ -514,9 +519,14 @@ svn_repos_parse_dumpstream2 (svn_stream_
/* Keep reading blank lines until we discover a new record, or until
the stream runs out. */
SVN_ERR (svn_stream_readline (stream, &linebuf, "\n", &eof, linepool));
-
+
if (eof)
- break; /* end of stream, go home. */
+ {
+ if (svn_stringbuf_isempty (linebuf))
+ break; /* end of stream, go home. */
+ else
+ return stream_ran_dry ();
+ }
if ((linebuf->len == 0) || (apr_isspace (linebuf->data[0])))
continue; /* empty line ... loop */
@@ -779,6 +789,7 @@ make_node_baton (apr_hash_t *headers,
nb->kind = svn_node_dir;
}
+ nb->action = (enum svn_node_action)(-1); /* because 0 is a valid action code */
if ((val = apr_hash_get (headers, SVN_REPOS_DUMPFILE_NODE_ACTION,
APR_HASH_KEY_STRING)))
{
@@ -792,6 +803,7 @@ make_node_baton (apr_hash_t *headers,
nb->action = svn_node_action_replace;
}
+ nb->copyfrom_rev = SVN_INVALID_REVNUM;
if ((val = apr_hash_get (headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV,
APR_HASH_KEY_STRING)))
{
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Feb 7 01:47:43 2006