diff options
Diffstat (limited to 'vcs-svn')
-rw-r--r-- | vcs-svn/LICENSE | 32 | ||||
-rw-r--r-- | vcs-svn/fast_export.c | 365 | ||||
-rw-r--r-- | vcs-svn/line_buffer.c | 126 | ||||
-rw-r--r-- | vcs-svn/line_buffer.txt | 77 | ||||
-rw-r--r-- | vcs-svn/sliding_window.c | 79 | ||||
-rw-r--r-- | vcs-svn/svndiff.c | 309 | ||||
-rw-r--r-- | vcs-svn/svndump.c | 540 |
7 files changed, 0 insertions, 1528 deletions
diff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE deleted file mode 100644 index eb91858b82..0000000000 --- a/vcs-svn/LICENSE +++ /dev/null @@ -1,32 +0,0 @@ -Copyright (C) 2010 David Barr <david.barr@cordelta.com>. -All rights reserved. - -Copyright (C) 2010 Jonathan Nieder <jrnieder@gmail.com>. - -Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH, -Frankfurt/Main, Germany -and others, see http://svn2cc.sarovar.org - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice(s), this list of conditions and the following disclaimer - unmodified other than the allowable addition of one or more - copyright notices. -2. Redistributions in binary form must reproduce the above copyright - notice(s), this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c deleted file mode 100644 index b5b8913cb0..0000000000 --- a/vcs-svn/fast_export.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Licensed under a two-clause BSD-style license. - * See LICENSE for details. - */ - -#include "cache.h" -#include "quote.h" -#include "fast_export.h" -#include "strbuf.h" -#include "svndiff.h" -#include "sliding_window.h" -#include "line_buffer.h" - -#define MAX_GITSVN_LINE_LEN 4096 - -static uint32_t first_commit_done; -static struct line_buffer postimage = LINE_BUFFER_INIT; -static struct line_buffer report_buffer = LINE_BUFFER_INIT; - -/* NEEDSWORK: move to fast_export_init() */ -static int init_postimage(void) -{ - static int postimage_initialized; - if (postimage_initialized) - return 0; - postimage_initialized = 1; - return buffer_tmpfile_init(&postimage); -} - -void fast_export_init(int fd) -{ - first_commit_done = 0; - if (buffer_fdinit(&report_buffer, fd)) - die_errno("cannot read from file descriptor %d", fd); -} - -void fast_export_deinit(void) -{ - if (buffer_deinit(&report_buffer)) - die_errno("error closing fast-import feedback stream"); -} - -void fast_export_delete(const char *path) -{ - putchar('D'); - putchar(' '); - quote_c_style(path, NULL, stdout, 0); - putchar('\n'); -} - -static void fast_export_truncate(const char *path, uint32_t mode) -{ - fast_export_modify(path, mode, "inline"); - printf("data 0\n\n"); -} - -void fast_export_modify(const char *path, uint32_t mode, const char *dataref) -{ - /* Mode must be 100644, 100755, 120000, or 160000. */ - if (!dataref) { - fast_export_truncate(path, mode); - return; - } - printf("M %06"PRIo32" %s ", mode, dataref); - quote_c_style(path, NULL, stdout, 0); - putchar('\n'); -} - -void fast_export_begin_note(uint32_t revision, const char *author, - const char *log, timestamp_t timestamp, const char *note_ref) -{ - static int firstnote = 1; - size_t loglen = strlen(log); - printf("commit %s\n", note_ref); - printf("committer %s <%s@%s> %"PRItime" +0000\n", author, author, "local", timestamp); - printf("data %"PRIuMAX"\n", (uintmax_t)loglen); - fwrite(log, loglen, 1, stdout); - if (firstnote) { - if (revision > 1) - printf("from %s^0", note_ref); - firstnote = 0; - } - fputc('\n', stdout); -} - -void fast_export_note(const char *committish, const char *dataref) -{ - printf("N %s %s\n", dataref, committish); -} - -static char gitsvnline[MAX_GITSVN_LINE_LEN]; -void fast_export_begin_commit(uint32_t revision, const char *author, - const struct strbuf *log, - const char *uuid, const char *url, - timestamp_t timestamp, const char *local_ref) -{ - static const struct strbuf empty = STRBUF_INIT; - if (!log) - log = ∅ - if (*uuid && *url) { - snprintf(gitsvnline, MAX_GITSVN_LINE_LEN, - "\n\ngit-svn-id: %s@%"PRIu32" %s\n", - url, revision, uuid); - } else { - *gitsvnline = '\0'; - } - printf("commit %s\n", local_ref); - printf("mark :%"PRIu32"\n", revision); - printf("committer %s <%s@%s> %"PRItime" +0000\n", - *author ? author : "nobody", - *author ? author : "nobody", - *uuid ? uuid : "local", timestamp); - printf("data %"PRIuMAX"\n", - (uintmax_t) (log->len + strlen(gitsvnline))); - fwrite(log->buf, log->len, 1, stdout); - printf("%s\n", gitsvnline); - if (!first_commit_done) { - if (revision > 1) - printf("from :%"PRIu32"\n", revision - 1); - first_commit_done = 1; - } -} - -void fast_export_end_commit(uint32_t revision) -{ - printf("progress Imported commit %"PRIu32".\n\n", revision); -} - -static void ls_from_rev(uint32_t rev, const char *path) -{ - /* ls :5 path/to/old/file */ - printf("ls :%"PRIu32" ", rev); - quote_c_style(path, NULL, stdout, 0); - putchar('\n'); - fflush(stdout); -} - -static void ls_from_active_commit(const char *path) -{ - /* ls "path/to/file" */ - printf("ls \""); - quote_c_style(path, NULL, stdout, 1); - printf("\"\n"); - fflush(stdout); -} - -static const char *get_response_line(void) -{ - const char *line = buffer_read_line(&report_buffer); - if (line) - return line; - if (buffer_ferror(&report_buffer)) - die_errno("error reading from fast-import"); - die("unexpected end of fast-import feedback"); -} - -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"); -} - -static int parse_cat_response_line(const char *header, off_t *len) -{ - uintmax_t n; - const char *type; - const char *end; - - if (ends_with(header, " missing")) - return error("cat-blob reports missing blob: %s", header); - type = strstr(header, " blob "); - if (!type) - return error("cat-blob header has wrong object type: %s", header); - n = strtoumax(type + strlen(" blob "), (char **) &end, 10); - if (end == type + strlen(" blob ")) - return error("cat-blob header does not contain length: %s", header); - if (memchr(type + strlen(" blob "), '-', end - type - strlen(" blob "))) - return error("cat-blob header contains negative length: %s", header); - if (n == UINTMAX_MAX || n > maximum_signed_value_of_type(off_t)) - return error("blob too large for current definition of off_t"); - *len = n; - if (*end) - return error("cat-blob header contains garbage after length: %s", header); - return 0; -} - -static void check_preimage_overflow(off_t a, off_t b) -{ - if (signed_add_overflows(a, b)) - die("blob too large for current definition of off_t"); -} - -static long apply_delta(off_t len, struct line_buffer *input, - const char *old_data, uint32_t old_mode) -{ - long ret; - struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, 0); - FILE *out; - - if (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage))) - die("cannot open temporary file for blob retrieval"); - if (old_data) { - const char *response; - printf("cat-blob %s\n", old_data); - fflush(stdout); - response = get_response_line(); - if (parse_cat_response_line(response, &preimage.max_off)) - die("invalid cat-blob response: %s", response); - check_preimage_overflow(preimage.max_off, 1); - } - if (old_mode == S_IFLNK) { - strbuf_addstr(&preimage.buf, "link "); - check_preimage_overflow(preimage.max_off, strlen("link ")); - preimage.max_off += strlen("link "); - check_preimage_overflow(preimage.max_off, 1); - } - if (svndiff0_apply(input, len, &preimage, out)) - die("cannot apply delta"); - if (old_data) { - /* Read the remainder of preimage and trailing newline. */ - assert(!signed_add_overflows(preimage.max_off, 1)); - preimage.max_off++; /* room for newline */ - if (move_window(&preimage, preimage.max_off - 1, 1)) - die("cannot seek to end of input"); - if (preimage.buf.buf[0] != '\n') - die("missing newline after cat-blob response"); - } - ret = buffer_tmpfile_prepare_to_read(&postimage); - if (ret < 0) - die("cannot read temporary file for blob retrieval"); - strbuf_release(&preimage.buf); - return ret; -} - -void fast_export_buf_to_data(const struct strbuf *data) -{ - printf("data %"PRIuMAX"\n", (uintmax_t)data->len); - fwrite(data->buf, data->len, 1, stdout); - fputc('\n', stdout); -} - -void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input) -{ - assert(len >= 0); - if (mode == S_IFLNK) { - /* svn symlink blobs start with "link " */ - if (len < 5) - die("invalid dump: symlink too short for \"link\" prefix"); - len -= 5; - if (buffer_skip_bytes(input, 5) != 5) - die_short_read(input); - } - printf("data %"PRIuMAX"\n", (uintmax_t) len); - if (buffer_copy_bytes(input, len) != len) - die_short_read(input); - fputc('\n', stdout); -} - -static int parse_ls_response(const char *response, uint32_t *mode, - struct strbuf *dataref) -{ - const char *tab; - const char *response_end; - - assert(response); - response_end = response + strlen(response); - - if (*response == 'm') { /* Missing. */ - errno = ENOENT; - return -1; - } - - /* Mode. */ - if (response_end - response < (signed) strlen("100644") || - response[strlen("100644")] != ' ') - die("invalid ls response: missing mode: %s", response); - *mode = 0; - for (; *response != ' '; response++) { - char ch = *response; - if (ch < '0' || ch > '7') - die("invalid ls response: mode is not octal: %s", response); - *mode *= 8; - *mode += ch - '0'; - } - - /* ' blob ' or ' tree ' */ - if (response_end - response < (signed) strlen(" blob ") || - (response[1] != 'b' && response[1] != 't')) - die("unexpected ls response: not a tree or blob: %s", response); - response += strlen(" blob "); - - /* Dataref. */ - tab = memchr(response, '\t', response_end - response); - if (!tab) - die("invalid ls response: missing tab: %s", response); - strbuf_add(dataref, response, tab - response); - return 0; -} - -int fast_export_ls_rev(uint32_t rev, const char *path, - uint32_t *mode, struct strbuf *dataref) -{ - ls_from_rev(rev, path); - return parse_ls_response(get_response_line(), mode, dataref); -} - -int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref) -{ - ls_from_active_commit(path); - return parse_ls_response(get_response_line(), mode, dataref); -} - -const char *fast_export_read_path(const char *path, uint32_t *mode_out) -{ - int err; - static struct strbuf buf = STRBUF_INIT; - - strbuf_reset(&buf); - err = fast_export_ls(path, mode_out, &buf); - if (err) { - if (errno != ENOENT) - BUG("unexpected fast_export_ls error: %s", - strerror(errno)); - /* Treat missing paths as directories. */ - *mode_out = S_IFDIR; - return NULL; - } - return buf.buf; -} - -void fast_export_copy(uint32_t revision, const char *src, const char *dst) -{ - int err; - uint32_t mode; - static struct strbuf data = STRBUF_INIT; - - strbuf_reset(&data); - err = fast_export_ls_rev(revision, src, &mode, &data); - if (err) { - if (errno != ENOENT) - BUG("unexpected fast_export_ls_rev error: %s", - strerror(errno)); - fast_export_delete(dst); - return; - } - fast_export_modify(dst, mode, data.buf); -} - -void fast_export_blob_delta(uint32_t mode, - uint32_t old_mode, const char *old_data, - off_t len, struct line_buffer *input) -{ - long postimage_len; - - assert(len >= 0); - postimage_len = apply_delta(len, input, old_data, old_mode); - if (mode == S_IFLNK) { - buffer_skip_bytes(&postimage, strlen("link ")); - postimage_len -= strlen("link "); - } - printf("data %ld\n", postimage_len); - buffer_copy_bytes(&postimage, postimage_len); - fputc('\n', stdout); -} diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c deleted file mode 100644 index e416caf8a4..0000000000 --- a/vcs-svn/line_buffer.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed under a two-clause BSD-style license. - * See LICENSE for details. - */ - -#include "git-compat-util.h" -#include "line_buffer.h" -#include "strbuf.h" - -#define COPY_BUFFER_LEN 4096 - -int buffer_init(struct line_buffer *buf, const char *filename) -{ - buf->infile = filename ? fopen(filename, "r") : stdin; - if (!buf->infile) - return -1; - return 0; -} - -int buffer_fdinit(struct line_buffer *buf, int fd) -{ - buf->infile = fdopen(fd, "r"); - if (!buf->infile) - return -1; - return 0; -} - -int buffer_tmpfile_init(struct line_buffer *buf) -{ - buf->infile = tmpfile(); - if (!buf->infile) - return -1; - return 0; -} - -int buffer_deinit(struct line_buffer *buf) -{ - int err; - if (buf->infile == stdin) - return ferror(buf->infile); - err = ferror(buf->infile); - err |= fclose(buf->infile); - return err; -} - -FILE *buffer_tmpfile_rewind(struct line_buffer *buf) -{ - rewind(buf->infile); - return buf->infile; -} - -long buffer_tmpfile_prepare_to_read(struct line_buffer *buf) -{ - long pos = ftell(buf->infile); - if (pos < 0) - return error_errno("ftell error"); - if (fseek(buf->infile, 0, SEEK_SET)) - return error_errno("seek error"); - 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); -} - -/* Read a line without trailing newline. */ -char *buffer_read_line(struct line_buffer *buf) -{ - char *end; - if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile)) - /* Error or data exhausted. */ - return NULL; - end = buf->line_buffer + strlen(buf->line_buffer); - if (end[-1] == '\n') - end[-1] = '\0'; - else if (feof(buf->infile)) - ; /* No newline at end of file. That's fine. */ - else - /* - * Line was too long. - * There is probably a saner way to deal with this, - * but for now let's return an error. - */ - return NULL; - return buf->line_buffer; -} - -size_t buffer_read_binary(struct line_buffer *buf, - struct strbuf *sb, size_t size) -{ - return strbuf_fread(sb, size, buf->infile); -} - -off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes) -{ - char byte_buffer[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); - done += in; - fwrite(byte_buffer, 1, in, stdout); - if (ferror(stdout)) - return done + buffer_skip_bytes(buf, nbytes - done); - } - return done; -} - -off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes) -{ - char byte_buffer[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; - done += fread(byte_buffer, 1, in, buf->infile); - } - return done; -} diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt deleted file mode 100644 index 8e139eb22d..0000000000 --- a/vcs-svn/line_buffer.txt +++ /dev/null @@ -1,77 +0,0 @@ -line_buffer API -=============== - -The line_buffer library provides a convenient interface for -mostly-line-oriented input. - -Each line is not permitted to exceed 10000 bytes. The provided -functions are not thread-safe or async-signal-safe, and like -`fgets()`, they generally do not function correctly if interrupted -by a signal without SA_RESTART set. - -Calling sequence ----------------- - -The calling program: - - - initializes a `struct line_buffer` to LINE_BUFFER_INIT - - specifies a file to read with `buffer_init` - - processes input with `buffer_read_line`, `buffer_skip_bytes`, - and `buffer_copy_bytes` - - closes the file with `buffer_deinit`, perhaps to start over and - read another file. - -When finished, the caller can use `buffer_reset` to deallocate -resources. - -Using temporary files ---------------------- - -Temporary files provide a place to store data that should not outlive -the calling program. A program - - - initializes a `struct line_buffer` to LINE_BUFFER_INIT - - requests a temporary file with `buffer_tmpfile_init` - - acquires an output handle by calling `buffer_tmpfile_rewind` - - uses standard I/O functions like `fprintf` and `fwrite` to fill - the temporary file - - declares writing is over with `buffer_tmpfile_prepare_to_read` - - can re-read what was written with `buffer_read_line`, - `buffer_copy_bytes`, and so on - - can reuse the temporary file by calling `buffer_tmpfile_rewind` - again - - removes the temporary file with `buffer_deinit`, perhaps to - reuse the line_buffer for some other file. - -When finished, the calling program can use `buffer_reset` to deallocate -resources. - -Functions ---------- - -`buffer_init`, `buffer_fdinit`:: - Open the named file or file descriptor for input. - buffer_init(buf, NULL) prepares to read from stdin. - On failure, returns -1 (with errno indicating the nature - of the failure). - -`buffer_deinit`:: - Stop reading from the current file (closing it unless - it was stdin). Returns nonzero if `fclose` fails or - the error indicator was set. - -`buffer_read_line`:: - Read a line and strip off the trailing newline. - On failure or end of file, returns NULL. - -`buffer_copy_bytes`:: - Read `len` bytes of input and dump them to the standard output - stream. Returns early for error or end of file. - -`buffer_skip_bytes`:: - Discards `len` bytes from the input stream (stopping early - if necessary because of an error or eof). Return value is - the number of bytes successfully read. - -`buffer_reset`:: - Deallocates non-static buffers. diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c deleted file mode 100644 index 06d273c9e8..0000000000 --- a/vcs-svn/sliding_window.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed under a two-clause BSD-style license. - * See LICENSE for details. - */ - -#include "git-compat-util.h" -#include "sliding_window.h" -#include "line_buffer.h" -#include "strbuf.h" - -static int input_error(struct line_buffer *file) -{ - if (!buffer_ferror(file)) - return error("delta preimage ends early"); - return error_errno("cannot read delta preimage"); -} - -static int skip_or_whine(struct line_buffer *file, off_t gap) -{ - if (buffer_skip_bytes(file, gap) != gap) - return input_error(file); - return 0; -} - -static int read_to_fill_or_whine(struct line_buffer *file, - struct strbuf *buf, size_t width) -{ - buffer_read_binary(file, buf, width - buf->len); - if (buf->len != width) - return input_error(file); - return 0; -} - -static int check_offset_overflow(off_t offset, uintmax_t len) -{ - if (len > maximum_signed_value_of_type(off_t)) - return error("unrepresentable length in delta: " - "%"PRIuMAX" > OFF_MAX", len); - if (signed_add_overflows(offset, (off_t) len)) - return error("unrepresentable offset in delta: " - "%"PRIuMAX" + %"PRIuMAX" > OFF_MAX", - (uintmax_t) offset, len); - return 0; -} - -int move_window(struct sliding_view *view, off_t off, size_t width) -{ - off_t file_offset; - assert(view); - assert(view->width <= view->buf.len); - assert(!check_offset_overflow(view->off, view->buf.len)); - - if (check_offset_overflow(off, width)) - return -1; - if (off < view->off || off + width < view->off + view->width) - return error("invalid delta: window slides left"); - if (view->max_off >= 0 && view->max_off < off + (off_t) width) - return error("delta preimage ends early"); - - file_offset = view->off + view->buf.len; - if (off < file_offset) { - /* Move the overlapping region into place. */ - strbuf_remove(&view->buf, 0, off - view->off); - } else { - /* Seek ahead to skip the gap. */ - if (skip_or_whine(view->file, off - file_offset)) - return -1; - strbuf_setlen(&view->buf, 0); - } - - if (view->buf.len > width) - ; /* Already read. */ - else if (read_to_fill_or_whine(view->file, &view->buf, width)) - return -1; - - view->off = off; - view->width = width; - return 0; -} diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c deleted file mode 100644 index 75c753162a..0000000000 --- a/vcs-svn/svndiff.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Licensed under a two-clause BSD-style license. - * See LICENSE for details. - */ - -#include "git-compat-util.h" -#include "sliding_window.h" -#include "line_buffer.h" -#include "svndiff.h" - -/* - * svndiff0 applier - * - * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff. - * - * svndiff0 ::= 'SVN\0' window* - * window ::= int int int int int instructions inline_data; - * instructions ::= instruction*; - * instruction ::= view_selector int int - * | copyfrom_data int - * | packed_view_selector int - * | packed_copyfrom_data - * ; - * view_selector ::= copyfrom_source - * | copyfrom_target - * ; - * copyfrom_source ::= # binary 00 000000; - * copyfrom_target ::= # binary 01 000000; - * copyfrom_data ::= # binary 10 000000; - * packed_view_selector ::= # view_selector OR-ed with 6 bit value; - * packed_copyfrom_data ::= # copyfrom_data OR-ed with 6 bit value; - * int ::= highdigit* lowdigit; - * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value; - * lowdigit ::= # 7 bit value; - */ - -#define INSN_MASK 0xc0 -#define INSN_COPYFROM_SOURCE 0x00 -#define INSN_COPYFROM_TARGET 0x40 -#define INSN_COPYFROM_DATA 0x80 -#define OPERAND_MASK 0x3f - -#define VLI_CONTINUE 0x80 -#define VLI_DIGIT_MASK 0x7f -#define VLI_BITS_PER_DIGIT 7 - -struct window { - struct sliding_view *in; - struct strbuf out; - struct strbuf instructions; - struct strbuf data; -}; - -#define WINDOW_INIT(w) { (w), STRBUF_INIT, STRBUF_INIT, STRBUF_INIT } - -static void window_release(struct window *ctx) -{ - strbuf_release(&ctx->out); - strbuf_release(&ctx->instructions); - strbuf_release(&ctx->data); -} - -static int write_strbuf(struct strbuf *sb, FILE *out) -{ - if (fwrite(sb->buf, 1, sb->len, out) == sb->len) /* Success. */ - return 0; - return error_errno("cannot write delta postimage"); -} - -static int error_short_read(struct line_buffer *input) -{ - if (buffer_ferror(input)) - return error_errno("error reading delta"); - return error("invalid delta: unexpected end of file"); -} - -static int read_chunk(struct line_buffer *delta, off_t *delta_len, - struct strbuf *buf, size_t len) -{ - assert(*delta_len >= 0); - strbuf_reset(buf); - if (len > (uintmax_t) *delta_len || - buffer_read_binary(delta, buf, len) != len) - return error_short_read(delta); - *delta_len -= buf->len; - return 0; -} - -static int read_magic(struct line_buffer *in, off_t *len) -{ - static const char magic[] = {'S', 'V', 'N', '\0'}; - struct strbuf sb = STRBUF_INIT; - - if (read_chunk(in, len, &sb, sizeof(magic))) { - strbuf_release(&sb); - return -1; - } - if (memcmp(sb.buf, magic, sizeof(magic))) { - strbuf_release(&sb); - return error("invalid delta: unrecognized file type"); - } - strbuf_release(&sb); - return 0; -} - -static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len) -{ - uintmax_t rv = 0; - off_t sz; - for (sz = *len; sz; sz--) { - const int ch = buffer_read_char(in); - if (ch == EOF) - break; - - rv <<= VLI_BITS_PER_DIGIT; - rv += (ch & VLI_DIGIT_MASK); - if (ch & VLI_CONTINUE) - continue; - - *result = rv; - *len = sz - 1; - return 0; - } - return error_short_read(in); -} - -static int parse_int(const char **buf, size_t *result, const char *end) -{ - size_t rv = 0; - const char *pos; - for (pos = *buf; pos != end; pos++) { - unsigned char ch = *pos; - - rv <<= VLI_BITS_PER_DIGIT; - rv += (ch & VLI_DIGIT_MASK); - if (ch & VLI_CONTINUE) - continue; - - *result = rv; - *buf = pos + 1; - return 0; - } - return error("invalid delta: unexpected end of instructions section"); -} - -static int read_offset(struct line_buffer *in, off_t *result, off_t *len) -{ - uintmax_t val; - if (read_int(in, &val, len)) - return -1; - if (val > maximum_signed_value_of_type(off_t)) - return error("unrepresentable offset in delta: %"PRIuMAX"", val); - *result = val; - return 0; -} - -static int read_length(struct line_buffer *in, size_t *result, off_t *len) -{ - uintmax_t val; - if (read_int(in, &val, len)) - return -1; - if (val > SIZE_MAX) - return error("unrepresentable length in delta: %"PRIuMAX"", val); - *result = val; - return 0; -} - -static int copyfrom_source(struct window *ctx, const char **instructions, - size_t nbytes, const char *insns_end) -{ - size_t offset; - if (parse_int(instructions, &offset, insns_end)) - return -1; - if (unsigned_add_overflows(offset, nbytes) || - offset + nbytes > ctx->in->width) - return error("invalid delta: copies source data outside view"); - strbuf_add(&ctx->out, ctx->in->buf.buf + offset, nbytes); - return 0; -} - -static int copyfrom_target(struct window *ctx, const char **instructions, - size_t nbytes, const char *instructions_end) -{ - size_t offset; - if (parse_int(instructions, &offset, instructions_end)) - return -1; - if (offset >= ctx->out.len) - return error("invalid delta: copies from the future"); - for (; nbytes > 0; nbytes--) - strbuf_addch(&ctx->out, ctx->out.buf[offset++]); - return 0; -} - -static int copyfrom_data(struct window *ctx, size_t *data_pos, size_t nbytes) -{ - const size_t pos = *data_pos; - if (unsigned_add_overflows(pos, nbytes) || - pos + nbytes > ctx->data.len) - return error("invalid delta: copies unavailable inline data"); - strbuf_add(&ctx->out, ctx->data.buf + pos, nbytes); - *data_pos += nbytes; - return 0; -} - -static int parse_first_operand(const char **buf, size_t *out, const char *end) -{ - size_t result = (unsigned char) *(*buf)++ & OPERAND_MASK; - if (result) { /* immediate operand */ - *out = result; - return 0; - } - return parse_int(buf, out, end); -} - -static int execute_one_instruction(struct window *ctx, - const char **instructions, size_t *data_pos) -{ - unsigned int instruction; - const char *insns_end = ctx->instructions.buf + ctx->instructions.len; - size_t nbytes; - assert(ctx); - assert(instructions && *instructions); - assert(data_pos); - - instruction = (unsigned char) **instructions; - if (parse_first_operand(instructions, &nbytes, insns_end)) - return -1; - switch (instruction & INSN_MASK) { - case INSN_COPYFROM_SOURCE: - return copyfrom_source(ctx, instructions, nbytes, insns_end); - case INSN_COPYFROM_TARGET: - return copyfrom_target(ctx, instructions, nbytes, insns_end); - case INSN_COPYFROM_DATA: - return copyfrom_data(ctx, data_pos, nbytes); - default: - return error("invalid delta: unrecognized instruction"); - } -} - -static int apply_window_in_core(struct window *ctx) -{ - const char *instructions; - size_t data_pos = 0; - - /* - * Fill ctx->out.buf using data from the source, target, - * and inline data views. - */ - for (instructions = ctx->instructions.buf; - instructions != ctx->instructions.buf + ctx->instructions.len; - ) - if (execute_one_instruction(ctx, &instructions, &data_pos)) - return -1; - if (data_pos != ctx->data.len) - return error("invalid delta: does not copy all inline data"); - return 0; -} - -static int apply_one_window(struct line_buffer *delta, off_t *delta_len, - struct sliding_view *preimage, FILE *out) -{ - int rv = -1; - struct window ctx = WINDOW_INIT(preimage); - size_t out_len; - size_t instructions_len; - size_t data_len; - assert(delta_len); - - /* "source view" offset and length already handled; */ - if (read_length(delta, &out_len, delta_len) || - read_length(delta, &instructions_len, delta_len) || - read_length(delta, &data_len, delta_len) || - read_chunk(delta, delta_len, &ctx.instructions, instructions_len) || - read_chunk(delta, delta_len, &ctx.data, data_len)) - goto error_out; - strbuf_grow(&ctx.out, out_len); - if (apply_window_in_core(&ctx)) - goto error_out; - if (ctx.out.len != out_len) { - rv = error("invalid delta: incorrect postimage length"); - goto error_out; - } - if (write_strbuf(&ctx.out, out)) - goto error_out; - rv = 0; -error_out: - window_release(&ctx); - return rv; -} - -int svndiff0_apply(struct line_buffer *delta, off_t delta_len, - struct sliding_view *preimage, FILE *postimage) -{ - assert(delta && preimage && postimage && delta_len >= 0); - - if (read_magic(delta, &delta_len)) - return -1; - while (delta_len) { /* For each window: */ - off_t pre_off = -1; - size_t pre_len; - - if (read_offset(delta, &pre_off, &delta_len) || - read_length(delta, &pre_len, &delta_len) || - move_window(preimage, pre_off, pre_len) || - apply_one_window(delta, &delta_len, preimage, postimage)) - return -1; - } - return 0; -} diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c deleted file mode 100644 index 08d136b8cc..0000000000 --- a/vcs-svn/svndump.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Parse and rearrange a svnadmin dump. - * Create the dump with: - * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile - * - * Licensed under a two-clause BSD-style license. - * See LICENSE for details. - */ - -#include "cache.h" -#include "fast_export.h" -#include "line_buffer.h" -#include "strbuf.h" -#include "svndump.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 REPORT_FILENO 3 - -#define NODEACT_REPLACE 4 -#define NODEACT_DELETE 3 -#define NODEACT_ADD 2 -#define NODEACT_CHANGE 1 -#define NODEACT_UNKNOWN 0 - -/* States: */ -#define DUMP_CTX 0 /* dump metadata */ -#define REV_CTX 1 /* revision metadata */ -#define NODE_CTX 2 /* node metadata */ -#define INTERNODE_CTX 3 /* between nodes */ - -#define DATE_RFC2822_LEN 31 - -static struct line_buffer input = LINE_BUFFER_INIT; - -static struct { - uint32_t action, srcRev, type; - off_t prop_length, text_length; - struct strbuf src, dst; - uint32_t text_delta, prop_delta; -} node_ctx; - -static struct { - uint32_t revision; - timestamp_t timestamp; - struct strbuf log, author, note; -} rev_ctx; - -static struct { - uint32_t version; - struct strbuf uuid, url; -} dump_ctx; - -static void reset_node_ctx(char *fname) -{ - node_ctx.type = 0; - node_ctx.action = NODEACT_UNKNOWN; - node_ctx.prop_length = -1; - node_ctx.text_length = -1; - strbuf_reset(&node_ctx.src); - node_ctx.srcRev = 0; - strbuf_reset(&node_ctx.dst); - if (fname) - strbuf_addstr(&node_ctx.dst, fname); - node_ctx.text_delta = 0; - node_ctx.prop_delta = 0; -} - -static void reset_rev_ctx(uint32_t revision) -{ - rev_ctx.revision = revision; - rev_ctx.timestamp = 0; - strbuf_reset(&rev_ctx.log); - strbuf_reset(&rev_ctx.author); - strbuf_reset(&rev_ctx.note); -} - -static void reset_dump_ctx(const char *url) -{ - strbuf_reset(&dump_ctx.url); - if (url) - strbuf_addstr(&dump_ctx.url, url); - dump_ctx.version = 1; - strbuf_reset(&dump_ctx.uuid); -} - -static void handle_property(const struct strbuf *key_buf, - struct strbuf *val, - uint32_t *type_set) -{ - 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"); - strbuf_swap(&rev_ctx.log, val); - break; - case sizeof("svn:author"): - if (constcmp(key, "svn:author")) - break; - if (!val) - strbuf_reset(&rev_ctx.author); - else - strbuf_swap(&rev_ctx.author, val); - break; - case sizeof("svn:date"): - if (constcmp(key, "svn:date")) - break; - if (!val) - die("invalid dump: unsets svn:date"); - if (parse_date_basic(val->buf, &rev_ctx.timestamp, NULL)) - warning("invalid timestamp: %s", val->buf); - 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; - die("invalid dump: sets type twice"); - } - if (!val) { - node_ctx.type = S_IFREG | 0644; - return; - } - *type_set = 1; - node_ctx.type = keylen == strlen("svn:executable") ? - (S_IFREG | 0755) : - S_IFLNK; - } -} - -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) -{ - static struct strbuf key = STRBUF_INIT; - static struct strbuf val = STRBUF_INIT; - const char *t; - /* - * NEEDSWORK: to support simple mode changes like - * K 11 - * svn:special - * V 1 - * * - * D 14 - * svn:executable - * we keep track of whether a mode has been set and reset to - * plain file only if not. We should be keeping track of the - * symlink and executable bits separately instead. - */ - uint32_t type_set = 0; - while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) { - uint32_t len; - const char type = t[0]; - int ch; - - if (!type || t[1] != ' ') - die("invalid property line: %s", t); - len = atoi(&t[2]); - strbuf_reset(&val); - buffer_read_binary(&input, &val, len); - if (val.len < 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.buf); - - switch (type) { - case 'K': - strbuf_swap(&key, &val); - continue; - case 'D': - handle_property(&val, NULL, &type_set); - continue; - case 'V': - handle_property(&key, &val, &type_set); - strbuf_reset(&key); - continue; - default: - die("invalid property line: %s", t); - } - } -} - -static void handle_node(void) -{ - const uint32_t type = node_ctx.type; - const int have_props = node_ctx.prop_length != -1; - const int have_text = node_ctx.text_length != -1; - /* - * Old text for this node: - * NULL - directory or bug - * empty_blob - empty - * "<dataref>" - data retrievable from fast-import - */ - static const char *const empty_blob = "::empty::"; - const char *old_data = NULL; - uint32_t old_mode = S_IFREG | 0644; - - if (node_ctx.action == NODEACT_DELETE) { - if (have_text || have_props || node_ctx.srcRev) - die("invalid dump: deletion node has " - "copyfrom info, text, or properties"); - fast_export_delete(node_ctx.dst.buf); - return; - } - if (node_ctx.action == NODEACT_REPLACE) { - fast_export_delete(node_ctx.dst.buf); - node_ctx.action = NODEACT_ADD; - } - if (node_ctx.srcRev) { - fast_export_copy(node_ctx.srcRev, node_ctx.src.buf, node_ctx.dst.buf); - if (node_ctx.action == NODEACT_ADD) - node_ctx.action = NODEACT_CHANGE; - } - if (have_text && type == S_IFDIR) - die("invalid dump: directories cannot have text attached"); - - /* - * Find old content (old_data) and decide on the new mode. - */ - if (node_ctx.action == NODEACT_CHANGE && !*node_ctx.dst.buf) { - if (type != S_IFDIR) - die("invalid dump: root of tree is not a regular file"); - old_data = NULL; - } else if (node_ctx.action == NODEACT_CHANGE) { - uint32_t mode; - old_data = fast_export_read_path(node_ctx.dst.buf, &mode); - if (mode == S_IFDIR && type != S_IFDIR) - die("invalid dump: cannot modify a directory into a file"); - if (mode != S_IFDIR && type == S_IFDIR) - die("invalid dump: cannot modify a file into a directory"); - node_ctx.type = mode; - old_mode = mode; - } else if (node_ctx.action == NODEACT_ADD) { - if (type == S_IFDIR) - old_data = NULL; - else if (have_text) - old_data = empty_blob; - else - die("invalid dump: adds node without text"); - } else { - die("invalid dump: Node-path block lacks Node-action"); - } - - /* - * Adjust mode to reflect properties. - */ - if (have_props) { - if (!node_ctx.prop_delta) - node_ctx.type = type; - if (node_ctx.prop_length) - read_props(); - } - - /* - * Save the result. - */ - if (type == S_IFDIR) /* directories are not tracked. */ - return; - assert(old_data); - if (old_data == empty_blob) - /* For the fast_export_* functions, NULL means empty. */ - old_data = NULL; - if (!have_text) { - fast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data); - return; - } - if (!node_ctx.text_delta) { - fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline"); - fast_export_data(node_ctx.type, node_ctx.text_length, &input); - return; - } - fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline"); - fast_export_blob_delta(node_ctx.type, old_mode, old_data, - node_ctx.text_length, &input); -} - -static void begin_revision(const char *remote_ref) -{ - if (!rev_ctx.revision) /* revision 0 gets no git commit. */ - return; - fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf, - &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf, - rev_ctx.timestamp, remote_ref); -} - -static void end_revision(const char *note_ref) -{ - struct strbuf mark = STRBUF_INIT; - if (rev_ctx.revision) { - fast_export_end_commit(rev_ctx.revision); - fast_export_begin_note(rev_ctx.revision, "remote-svn", - "Note created by remote-svn.", rev_ctx.timestamp, note_ref); - strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision); - fast_export_note(mark.buf, "inline"); - fast_export_buf_to_data(&rev_ctx.note); - strbuf_release(&mark); - } -} - -void svndump_read(const char *url, const char *local_ref, const char *notes_ref) -{ - char *val; - char *t; - uint32_t active_ctx = DUMP_CTX; - uint32_t len; - - reset_dump_ctx(url); - while ((t = buffer_read_line(&input))) { - val = strchr(t, ':'); - if (!val) - continue; - val++; - if (*val != ' ') - continue; - val++; - - /* 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); - 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 == REV_CTX) - begin_revision(local_ref); - if (active_ctx != DUMP_CTX) - end_revision(notes_ref); - active_ctx = REV_CTX; - reset_rev_ctx(atoi(val)); - strbuf_addf(&rev_ctx.note, "%s\n", t); - break; - case sizeof("Node-path"): - if (constcmp(t, "Node-")) - continue; - if (!constcmp(t + strlen("Node-"), "path")) { - if (active_ctx == NODE_CTX) - handle_node(); - if (active_ctx == REV_CTX) - begin_revision(local_ref); - active_ctx = NODE_CTX; - reset_node_ctx(val); - strbuf_addf(&rev_ctx.note, "%s\n", t); - break; - } - if (constcmp(t + strlen("Node-"), "kind")) - continue; - strbuf_addf(&rev_ctx.note, "%s\n", t); - if (!strcmp(val, "dir")) - node_ctx.type = S_IFDIR; - else if (!strcmp(val, "file")) - node_ctx.type = S_IFREG | 0644; - else - fprintf(stderr, "Unknown node-kind: %s\n", val); - break; - case sizeof("Node-action"): - if (constcmp(t, "Node-action")) - continue; - strbuf_addf(&rev_ctx.note, "%s\n", t); - if (!strcmp(val, "delete")) { - node_ctx.action = NODEACT_DELETE; - } else if (!strcmp(val, "add")) { - node_ctx.action = NODEACT_ADD; - } else if (!strcmp(val, "change")) { - node_ctx.action = NODEACT_CHANGE; - } else if (!strcmp(val, "replace")) { - node_ctx.action = NODEACT_REPLACE; - } else { - fprintf(stderr, "Unknown node-action: %s\n", val); - node_ctx.action = NODEACT_UNKNOWN; - } - break; - case sizeof("Node-copyfrom-path"): - if (constcmp(t, "Node-copyfrom-path")) - continue; - strbuf_reset(&node_ctx.src); - strbuf_addstr(&node_ctx.src, val); - strbuf_addf(&rev_ctx.note, "%s\n", t); - break; - case sizeof("Node-copyfrom-rev"): - if (constcmp(t, "Node-copyfrom-rev")) - continue; - node_ctx.srcRev = atoi(val); - strbuf_addf(&rev_ctx.note, "%s\n", t); - break; - case sizeof("Text-content-length"): - if (constcmp(t, "Text") && constcmp(t, "Prop")) - continue; - if (constcmp(t + 4, "-content-length")) - continue; - { - char *end; - uintmax_t len; - - len = strtoumax(val, &end, 10); - if (!isdigit(*val) || *end) - die("invalid dump: non-numeric length %s", val); - if (len > maximum_signed_value_of_type(off_t)) - die("unrepresentable length in dump: %s", val); - - if (*t == 'T') - node_ctx.text_length = (off_t) len; - else - node_ctx.prop_length = (off_t) len; - 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"); - break; - case sizeof("Content-length"): - if (constcmp(t, "Content-length")) - continue; - len = atoi(val); - 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) { - handle_node(); - active_ctx = INTERNODE_CTX; - } else { - fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", 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 == REV_CTX) - begin_revision(local_ref); - if (active_ctx != DUMP_CTX) - end_revision(notes_ref); -} - -static void init(int report_fd) -{ - fast_export_init(report_fd); - strbuf_init(&dump_ctx.uuid, 4096); - strbuf_init(&dump_ctx.url, 4096); - strbuf_init(&rev_ctx.log, 4096); - strbuf_init(&rev_ctx.author, 4096); - strbuf_init(&rev_ctx.note, 4096); - strbuf_init(&node_ctx.src, 4096); - strbuf_init(&node_ctx.dst, 4096); - reset_dump_ctx(NULL); - reset_rev_ctx(0); - reset_node_ctx(NULL); - return; -} - -int svndump_init(const char *filename) -{ - if (buffer_init(&input, filename)) - return error_errno("cannot open %s", filename ? filename : "NULL"); - init(REPORT_FILENO); - return 0; -} - -int svndump_init_fd(int in_fd, int back_fd) -{ - if(buffer_fdinit(&input, xdup(in_fd))) - return error_errno("cannot open fd %d", in_fd); - init(xdup(back_fd)); - return 0; -} - -void svndump_deinit(void) -{ - fast_export_deinit(); - reset_dump_ctx(NULL); - reset_rev_ctx(0); - reset_node_ctx(NULL); - strbuf_release(&rev_ctx.log); - strbuf_release(&rev_ctx.author); - strbuf_release(&rev_ctx.note); - strbuf_release(&node_ctx.src); - strbuf_release(&node_ctx.dst); - if (buffer_deinit(&input)) - fprintf(stderr, "Input error\n"); - if (ferror(stdout)) - fprintf(stderr, "Output error\n"); -} - -void svndump_reset(void) -{ - strbuf_release(&dump_ctx.uuid); - strbuf_release(&dump_ctx.url); - strbuf_release(&rev_ctx.log); - strbuf_release(&rev_ctx.author); -} |