Merge branch 'svn-fe' of git://repo.or.cz/git/jrn

* 'svn-fe' of git://repo.or.cz/git/jrn:
  vcs-svn: use strchr to find RFC822 delimiter
  vcs-svn: implement perfect hash for top-level keys
  vcs-svn: implement perfect hash for node-prop keys
  vcs-svn: use strbuf for author, UUID, and URL
  vcs-svn: use strbuf for revision log
  vcs-svn: improve reporting of input errors
  vcs-svn: make buffer_copy_bytes return length read
  vcs-svn: make buffer_skip_bytes return length read
  vcs-svn: improve support for reading large files
  vcs-svn: allow input errors to be detected promptly
  vcs-svn: simplify repo_modify_path and repo_copy
  vcs-svn: handle_node: use repo_read_path
  vcs-svn: introduce repo_read_path to check the content at a path
This commit is contained in:
Junio C Hamano 2011-03-22 20:51:07 -07:00
commit 785d6989da
8 changed files with 265 additions and 172 deletions

View File

@ -31,24 +31,24 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
}
static char gitsvnline[MAX_GITSVN_LINE_LEN];
void fast_export_commit(uint32_t revision, uint32_t author, char *log,
uint32_t uuid, uint32_t url,
void fast_export_commit(uint32_t revision, const char *author, char *log,
const char *uuid, const char *url,
unsigned long timestamp)
{
if (!log)
log = "";
if (~uuid && ~url) {
if (*uuid && *url) {
snprintf(gitsvnline, MAX_GITSVN_LINE_LEN,
"\n\ngit-svn-id: %s@%"PRIu32" %s\n",
pool_fetch(url), revision, pool_fetch(uuid));
url, revision, uuid);
} else {
*gitsvnline = '\0';
}
printf("commit refs/heads/master\n");
printf("committer %s <%s@%s> %ld +0000\n",
~author ? pool_fetch(author) : "nobody",
~author ? pool_fetch(author) : "nobody",
~uuid ? pool_fetch(uuid) : "local", timestamp);
*author ? author : "nobody",
*author ? author : "nobody",
*uuid ? uuid : "local", timestamp);
printf("data %"PRIu32"\n%s%s\n",
(uint32_t) (strlen(log) + strlen(gitsvnline)),
log, gitsvnline);
@ -63,14 +63,23 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
printf("progress Imported commit %"PRIu32".\n\n", revision);
}
static void die_short_read(struct line_buffer *input)
{
if (buffer_ferror(input))
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, struct line_buffer *input)
{
if (mode == REPO_MODE_LNK) {
/* svn symlink blobs start with "link " */
buffer_skip_bytes(input, 5);
len -= 5;
if (buffer_skip_bytes(input, 5) != 5)
die_short_read(input);
}
printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
buffer_copy_bytes(input, len);
if (buffer_copy_bytes(input, len) != len)
die_short_read(input);
fputc('\n', stdout);
}

View File

@ -6,8 +6,9 @@
void fast_export_delete(uint32_t depth, uint32_t *path);
void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
uint32_t mark);
void fast_export_commit(uint32_t revision, uint32_t author, char *log,
uint32_t uuid, uint32_t url, unsigned long timestamp);
void fast_export_commit(uint32_t revision, const char *author, char *log,
const char *uuid, const char *url,
unsigned long timestamp);
void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
struct line_buffer *input);

View File

@ -59,6 +59,11 @@ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf)
return pos;
}
int buffer_ferror(struct line_buffer *buf)
{
return ferror(buf->infile);
}
int buffer_read_char(struct line_buffer *buf)
{
return fgetc(buf->infile);
@ -99,31 +104,32 @@ void buffer_read_binary(struct line_buffer *buf,
strbuf_fread(sb, size, buf->infile);
}
void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)
off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
{
char byte_buffer[COPY_BUFFER_LEN];
uint32_t in;
while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {
in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
off_t done = 0;
while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
off_t len = nbytes - done;
size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
in = fread(byte_buffer, 1, in, buf->infile);
len -= in;
done += in;
fwrite(byte_buffer, 1, in, stdout);
if (ferror(stdout)) {
buffer_skip_bytes(buf, len);
return;
}
if (ferror(stdout))
return done + buffer_skip_bytes(buf, nbytes - done);
}
return done;
}
void buffer_skip_bytes(struct line_buffer *buf, uint32_t len)
off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
{
char byte_buffer[COPY_BUFFER_LEN];
uint32_t in;
while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {
in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
in = fread(byte_buffer, 1, in, buf->infile);
len -= in;
off_t done = 0;
while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
off_t len = nbytes - done;
size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
done += fread(byte_buffer, 1, in, buf->infile);
}
return done;
}
void buffer_reset(struct line_buffer *buf)

View File

@ -21,11 +21,13 @@ int buffer_tmpfile_init(struct line_buffer *buf);
FILE *buffer_tmpfile_rewind(struct line_buffer *buf); /* prepare to write. */
long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);
int buffer_ferror(struct line_buffer *buf);
char *buffer_read_line(struct line_buffer *buf);
char *buffer_read_string(struct line_buffer *buf, uint32_t len);
int buffer_read_char(struct line_buffer *buf);
void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);
void buffer_copy_bytes(struct line_buffer *buf, uint32_t len);
void buffer_skip_bytes(struct line_buffer *buf, uint32_t len);
/* Returns number of bytes read (not necessarily written). */
off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);
off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);
#endif

View File

@ -76,7 +76,8 @@ Functions
`buffer_skip_bytes`::
Discards `len` bytes from the input stream (stopping early
if necessary because of an error or eof).
if necessary because of an error or eof). Return value is
the number of bytes successfully read.
`buffer_reset`::
Deallocates non-static buffers.

View File

@ -87,7 +87,8 @@ static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir)
return dir_pointer(new_o);
}
static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
static struct repo_dirent *repo_read_dirent(uint32_t revision,
const uint32_t *path)
{
uint32_t name = 0;
struct repo_dirent *key = dent_pointer(dent_alloc(1));
@ -105,7 +106,7 @@ static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
return dent;
}
static void repo_write_dirent(uint32_t *path, uint32_t mode,
static void repo_write_dirent(const uint32_t *path, uint32_t mode,
uint32_t content_offset, uint32_t del)
{
uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0;
@ -157,7 +158,24 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode,
dent_remove(&dir_pointer(parent_dir_o)->entries, dent);
}
uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst)
uint32_t repo_read_path(const uint32_t *path)
{
uint32_t content_offset = 0;
struct repo_dirent *dent = repo_read_dirent(active_commit, path);
if (dent != NULL)
content_offset = dent->content_offset;
return content_offset;
}
uint32_t repo_read_mode(const uint32_t *path)
{
struct repo_dirent *dent = repo_read_dirent(active_commit, path);
if (dent == NULL)
die("invalid dump: path to be modified is missing");
return dent->mode;
}
void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)
{
uint32_t mode = 0, content_offset = 0;
struct repo_dirent *src_dent;
@ -167,7 +185,6 @@ uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst)
content_offset = src_dent->content_offset;
repo_write_dirent(dst, mode, content_offset, 0);
}
return mode;
}
void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
@ -175,20 +192,6 @@ void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
repo_write_dirent(path, mode, blob_mark, 0);
}
uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark)
{
struct repo_dirent *src_dent;
src_dent = repo_read_dirent(active_commit, path);
if (!src_dent)
return 0;
if (!blob_mark)
blob_mark = src_dent->content_offset;
if (!mode)
mode = src_dent->mode;
repo_write_dirent(path, mode, blob_mark, 0);
return mode;
}
void repo_delete(uint32_t *path)
{
repo_write_dirent(path, 0, 0, 1);
@ -275,8 +278,8 @@ void repo_diff(uint32_t r1, uint32_t r2)
repo_commit_root_dir(commit_pointer(r2)));
}
void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
uint32_t url, unsigned long timestamp)
void repo_commit(uint32_t revision, const char *author, char *log,
const char *uuid, const char *url, unsigned long timestamp)
{
fast_export_commit(revision, author, log, uuid, url, timestamp);
dent_commit();

View File

@ -12,12 +12,14 @@
#define REPO_MAX_PATH_DEPTH 1000
uint32_t next_blob_mark(void);
uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst);
void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);
void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);
uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark);
uint32_t repo_read_path(const uint32_t *path);
uint32_t repo_read_mode(const uint32_t *path);
void repo_delete(uint32_t *path);
void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
uint32_t url, long unsigned timestamp);
void repo_commit(uint32_t revision, const char *author,
char *log, const char *uuid, const char *url,
long unsigned timestamp);
void repo_diff(uint32_t r1, uint32_t r2);
void repo_init(void);
void repo_reset(void);

View File

@ -11,8 +11,14 @@
#include "repo_tree.h"
#include "fast_export.h"
#include "line_buffer.h"
#include "obj_pool.h"
#include "string_pool.h"
#include "strbuf.h"
/*
* Compare start of string to literal of equal length;
* must be guarded by length test.
*/
#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
#define NODEACT_REPLACE 4
#define NODEACT_DELETE 3
@ -27,20 +33,8 @@
#define LENGTH_UNKNOWN (~0)
#define DATE_RFC2822_LEN 31
/* Create memory pool for log messages */
obj_pool_gen(log, char, 4096)
static struct line_buffer input = LINE_BUFFER_INIT;
static char *log_copy(uint32_t length, const char *log)
{
char *buffer;
log_free(log_pool.size);
buffer = log_pointer(log_alloc(length));
strncpy(buffer, log, length);
return buffer;
}
static struct {
uint32_t action, propLength, textLength, srcRev, type;
uint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];
@ -48,24 +42,16 @@ static struct {
} node_ctx;
static struct {
uint32_t revision, author;
uint32_t revision;
unsigned long timestamp;
char *log;
struct strbuf log, author;
} rev_ctx;
static struct {
uint32_t version, uuid, url;
uint32_t version;
struct strbuf uuid, url;
} dump_ctx;
static struct {
uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,
revision_number, node_path, node_kind, node_action,
node_copyfrom_path, node_copyfrom_rev, text_content_length,
prop_content_length, content_length, svn_fs_dump_format_version,
/* version 3 format */
text_delta, prop_delta;
} keys;
static void reset_node_ctx(char *fname)
{
node_ctx.type = 0;
@ -83,56 +69,58 @@ static void reset_rev_ctx(uint32_t revision)
{
rev_ctx.revision = revision;
rev_ctx.timestamp = 0;
rev_ctx.log = NULL;
rev_ctx.author = ~0;
strbuf_reset(&rev_ctx.log);
strbuf_reset(&rev_ctx.author);
}
static void reset_dump_ctx(uint32_t url)
static void reset_dump_ctx(const char *url)
{
dump_ctx.url = url;
strbuf_reset(&dump_ctx.url);
if (url)
strbuf_addstr(&dump_ctx.url, url);
dump_ctx.version = 1;
dump_ctx.uuid = ~0;
strbuf_reset(&dump_ctx.uuid);
}
static void init_keys(void)
{
keys.svn_log = pool_intern("svn:log");
keys.svn_author = pool_intern("svn:author");
keys.svn_date = pool_intern("svn:date");
keys.svn_executable = pool_intern("svn:executable");
keys.svn_special = pool_intern("svn:special");
keys.uuid = pool_intern("UUID");
keys.revision_number = pool_intern("Revision-number");
keys.node_path = pool_intern("Node-path");
keys.node_kind = pool_intern("Node-kind");
keys.node_action = pool_intern("Node-action");
keys.node_copyfrom_path = pool_intern("Node-copyfrom-path");
keys.node_copyfrom_rev = pool_intern("Node-copyfrom-rev");
keys.text_content_length = pool_intern("Text-content-length");
keys.prop_content_length = pool_intern("Prop-content-length");
keys.content_length = pool_intern("Content-length");
keys.svn_fs_dump_format_version = pool_intern("SVN-fs-dump-format-version");
/* version 3 format (Subversion 1.1.0) */
keys.text_delta = pool_intern("Text-delta");
keys.prop_delta = pool_intern("Prop-delta");
}
static void handle_property(uint32_t key, const char *val, uint32_t len,
static void handle_property(const struct strbuf *key_buf,
const char *val, uint32_t len,
uint32_t *type_set)
{
if (key == keys.svn_log) {
const char *key = key_buf->buf;
size_t keylen = key_buf->len;
switch (keylen + 1) {
case sizeof("svn:log"):
if (constcmp(key, "svn:log"))
break;
if (!val)
die("invalid dump: unsets svn:log");
/* Value length excludes terminating nul. */
rev_ctx.log = log_copy(len + 1, val);
} else if (key == keys.svn_author) {
rev_ctx.author = pool_intern(val);
} else if (key == keys.svn_date) {
strbuf_reset(&rev_ctx.log);
strbuf_add(&rev_ctx.log, val, len);
break;
case sizeof("svn:author"):
if (constcmp(key, "svn:author"))
break;
strbuf_reset(&rev_ctx.author);
if (val)
strbuf_add(&rev_ctx.author, val, len);
break;
case sizeof("svn:date"):
if (constcmp(key, "svn:date"))
break;
if (!val)
die("invalid dump: unsets svn:date");
if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
warning("invalid timestamp: %s", val);
} else if (key == keys.svn_executable || key == keys.svn_special) {
break;
case sizeof("svn:executable"):
case sizeof("svn:special"):
if (keylen == strlen("svn:executable") &&
constcmp(key, "svn:executable"))
break;
if (keylen == strlen("svn:special") &&
constcmp(key, "svn:special"))
break;
if (*type_set) {
if (!val)
return;
@ -143,15 +131,22 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,
return;
}
*type_set = 1;
node_ctx.type = key == keys.svn_executable ?
node_ctx.type = keylen == strlen("svn:executable") ?
REPO_MODE_EXE :
REPO_MODE_LNK;
}
}
static void die_short_read(void)
{
if (buffer_ferror(&input))
die_errno("error reading dump file");
die("invalid dump: unexpected end of file");
}
static void read_props(void)
{
uint32_t key = ~0;
static struct strbuf key = STRBUF_INIT;
const char *t;
/*
* NEEDSWORK: to support simple mode changes like
@ -170,25 +165,37 @@ static void read_props(void)
uint32_t len;
const char *val;
const char type = t[0];
int ch;
if (!type || t[1] != ' ')
die("invalid property line: %s\n", t);
len = atoi(&t[2]);
val = buffer_read_string(&input, len);
buffer_skip_bytes(&input, 1); /* Discard trailing newline. */
if (!val || strlen(val) != len)
die_short_read();
/* Discard trailing newline. */
ch = buffer_read_char(&input);
if (ch == EOF)
die_short_read();
if (ch != '\n')
die("invalid dump: expected newline after %s", val);
switch (type) {
case 'K':
key = pool_intern(val);
continue;
case 'D':
key = pool_intern(val);
strbuf_reset(&key);
if (val)
strbuf_add(&key, val, len);
if (type == 'K')
continue;
assert(type == 'D');
val = NULL;
len = 0;
/* fall through */
case 'V':
handle_property(key, val, len, &type_set);
key = ~0;
handle_property(&key, val, len, &type_set);
strbuf_reset(&key);
continue;
default:
die("invalid property line: %s\n", t);
@ -201,13 +208,14 @@ static void handle_node(void)
uint32_t mark = 0;
const uint32_t type = node_ctx.type;
const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
const int have_text = node_ctx.textLength != LENGTH_UNKNOWN;
if (node_ctx.text_delta)
die("text deltas not supported");
if (node_ctx.textLength != LENGTH_UNKNOWN)
if (have_text)
mark = next_blob_mark();
if (node_ctx.action == NODEACT_DELETE) {
if (mark || have_props || node_ctx.srcRev)
if (have_text || have_props || node_ctx.srcRev)
die("invalid dump: deletion node has "
"copyfrom info, text, or properties");
return repo_delete(node_ctx.dst);
@ -221,37 +229,47 @@ static void handle_node(void)
if (node_ctx.action == NODEACT_ADD)
node_ctx.action = NODEACT_CHANGE;
}
if (mark && type == REPO_MODE_DIR)
if (have_text && type == REPO_MODE_DIR)
die("invalid dump: directories cannot have text attached");
/*
* Decide on the new content (mark) and mode (node_ctx.type).
*/
if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {
if (type != REPO_MODE_DIR)
die("invalid dump: root of tree is not a regular file");
} else if (node_ctx.action == NODEACT_CHANGE) {
uint32_t mode = repo_modify_path(node_ctx.dst, 0, mark);
if (!mode)
die("invalid dump: path to be modified is missing");
uint32_t mode;
if (!have_text)
mark = repo_read_path(node_ctx.dst);
mode = repo_read_mode(node_ctx.dst);
if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
die("invalid dump: cannot modify a directory into a file");
if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)
die("invalid dump: cannot modify a file into a directory");
node_ctx.type = mode;
} else if (node_ctx.action == NODEACT_ADD) {
if (!mark && type != REPO_MODE_DIR)
if (!have_text && type != REPO_MODE_DIR)
die("invalid dump: adds node without text");
repo_add(node_ctx.dst, type, mark);
} else {
die("invalid dump: Node-path block lacks Node-action");
}
/*
* Adjust mode to reflect properties.
*/
if (have_props) {
const uint32_t old_mode = node_ctx.type;
if (!node_ctx.prop_delta)
node_ctx.type = type;
if (node_ctx.propLength)
read_props();
if (node_ctx.type != old_mode)
repo_modify_path(node_ctx.dst, node_ctx.type, mark);
}
if (mark)
/*
* Save the result.
*/
repo_add(node_ctx.dst, node_ctx.type, mark);
if (have_text)
fast_export_blob(node_ctx.type, mark,
node_ctx.textLength, &input);
}
@ -259,8 +277,9 @@ static void handle_node(void)
static void handle_revision(void)
{
if (rev_ctx.revision)
repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
repo_commit(rev_ctx.revision, rev_ctx.author.buf,
rev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,
rev_ctx.timestamp);
}
void svndump_read(const char *url)
@ -269,44 +288,65 @@ void svndump_read(const char *url)
char *t;
uint32_t active_ctx = DUMP_CTX;
uint32_t len;
uint32_t key;
reset_dump_ctx(pool_intern(url));
reset_dump_ctx(url);
while ((t = buffer_read_line(&input))) {
val = strstr(t, ": ");
val = strchr(t, ':');
if (!val)
continue;
*val++ = '\0';
*val++ = '\0';
key = pool_intern(t);
val++;
if (*val != ' ')
continue;
val++;
if (key == keys.svn_fs_dump_format_version) {
/* strlen(key) + 1 */
switch (val - t - 1) {
case sizeof("SVN-fs-dump-format-version"):
if (constcmp(t, "SVN-fs-dump-format-version"))
continue;
dump_ctx.version = atoi(val);
if (dump_ctx.version > 3)
die("expected svn dump format version <= 3, found %"PRIu32,
dump_ctx.version);
} else if (key == keys.uuid) {
dump_ctx.uuid = pool_intern(val);
} else if (key == keys.revision_number) {
break;
case sizeof("UUID"):
if (constcmp(t, "UUID"))
continue;
strbuf_reset(&dump_ctx.uuid);
strbuf_addstr(&dump_ctx.uuid, val);
break;
case sizeof("Revision-number"):
if (constcmp(t, "Revision-number"))
continue;
if (active_ctx == NODE_CTX)
handle_node();
if (active_ctx != DUMP_CTX)
handle_revision();
active_ctx = REV_CTX;
reset_rev_ctx(atoi(val));
} else if (key == keys.node_path) {
if (active_ctx == NODE_CTX)
handle_node();
active_ctx = NODE_CTX;
reset_node_ctx(val);
} else if (key == keys.node_kind) {
break;
case sizeof("Node-path"):
if (prefixcmp(t, "Node-"))
continue;
if (!constcmp(t + strlen("Node-"), "path")) {
if (active_ctx == NODE_CTX)
handle_node();
active_ctx = NODE_CTX;
reset_node_ctx(val);
break;
}
if (constcmp(t + strlen("Node-"), "kind"))
continue;
if (!strcmp(val, "dir"))
node_ctx.type = REPO_MODE_DIR;
else if (!strcmp(val, "file"))
node_ctx.type = REPO_MODE_BLB;
else
fprintf(stderr, "Unknown node-kind: %s\n", val);
} else if (key == keys.node_action) {
break;
case sizeof("Node-action"):
if (constcmp(t, "Node-action"))
continue;
if (!strcmp(val, "delete")) {
node_ctx.action = NODEACT_DELETE;
} else if (!strcmp(val, "add")) {
@ -319,21 +359,44 @@ void svndump_read(const char *url)
fprintf(stderr, "Unknown node-action: %s\n", val);
node_ctx.action = NODEACT_UNKNOWN;
}
} else if (key == keys.node_copyfrom_path) {
break;
case sizeof("Node-copyfrom-path"):
if (constcmp(t, "Node-copyfrom-path"))
continue;
pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, "/", val);
} else if (key == keys.node_copyfrom_rev) {
break;
case sizeof("Node-copyfrom-rev"):
if (constcmp(t, "Node-copyfrom-rev"))
continue;
node_ctx.srcRev = atoi(val);
} else if (key == keys.text_content_length) {
node_ctx.textLength = atoi(val);
} else if (key == keys.prop_content_length) {
break;
case sizeof("Text-content-length"):
if (!constcmp(t, "Text-content-length")) {
node_ctx.textLength = atoi(val);
break;
}
if (constcmp(t, "Prop-content-length"))
continue;
node_ctx.propLength = atoi(val);
} else if (key == keys.text_delta) {
node_ctx.text_delta = !strcmp(val, "true");
} else if (key == keys.prop_delta) {
break;
case sizeof("Text-delta"):
if (!constcmp(t, "Text-delta")) {
node_ctx.text_delta = !strcmp(val, "true");
break;
}
if (constcmp(t, "Prop-delta"))
continue;
node_ctx.prop_delta = !strcmp(val, "true");
} else if (key == keys.content_length) {
break;
case sizeof("Content-length"):
if (constcmp(t, "Content-length"))
continue;
len = atoi(val);
buffer_read_line(&input);
t = buffer_read_line(&input);
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) {
@ -341,10 +404,13 @@ void svndump_read(const char *url)
active_ctx = REV_CTX;
} else {
fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
buffer_skip_bytes(&input, len);
if (buffer_skip_bytes(&input, len) != len)
die_short_read();
}
}
}
if (buffer_ferror(&input))
die_short_read();
if (active_ctx == NODE_CTX)
handle_node();
if (active_ctx != DUMP_CTX)
@ -356,20 +422,23 @@ int svndump_init(const char *filename)
if (buffer_init(&input, filename))
return error("cannot open %s: %s", filename, strerror(errno));
repo_init();
reset_dump_ctx(~0);
strbuf_init(&dump_ctx.uuid, 4096);
strbuf_init(&dump_ctx.url, 4096);
strbuf_init(&rev_ctx.log, 4096);
strbuf_init(&rev_ctx.author, 4096);
reset_dump_ctx(NULL);
reset_rev_ctx(0);
reset_node_ctx(NULL);
init_keys();
return 0;
}
void svndump_deinit(void)
{
log_reset();
repo_reset();
reset_dump_ctx(~0);
reset_dump_ctx(NULL);
reset_rev_ctx(0);
reset_node_ctx(NULL);
strbuf_release(&rev_ctx.log);
if (buffer_deinit(&input))
fprintf(stderr, "Input error\n");
if (ferror(stdout))
@ -378,10 +447,10 @@ void svndump_deinit(void)
void svndump_reset(void)
{
log_reset();
buffer_reset(&input);
repo_reset();
reset_dump_ctx(~0);
reset_rev_ctx(0);
reset_node_ctx(NULL);
strbuf_release(&dump_ctx.uuid);
strbuf_release(&dump_ctx.url);
strbuf_release(&rev_ctx.log);
strbuf_release(&rev_ctx.author);
}