Reduce svndump frontend to a single source file.
[svn-fe.git] / svndump.c
bloba43ef965a65f25fe57f63de4896f7fabc0a98e10
1 /******************************************************************************
3 * Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,
4 * Frankfurt/Main, Germany
5 * and others, see http://svn2cc.sarovar.org
7 * Copyright (C) 2010 David Barr <david.barr@cordelta.com>.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice(s), this list of conditions and the following disclaimer
15 * unmodified other than the allowable addition of one or more
16 * copyright notices.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice(s), this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 ******************************************************************************/
37 * Parse and rearrange a svnadmin dump.
38 * Create the dump with:
39 * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
42 #include <stdint.h>
43 #include <string.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <time.h>
47 #include "repo_tree.h"
49 /**
50 * node was moved to somwhere else
51 * (this is not contained in the dump)
52 * (only used in the FileChangeSet)
54 #define NODEACT_REMOVE 5
56 /**
57 * node was moved from somwhere else
58 * (this is not contained in the dump)
59 * (only used in the FileChangeSet)
61 #define NODEACT_MOVE 4
63 /**
64 * not clear if moved (if deleted afterwards) or
65 * added as copy (which can not be modeled straight in ccase).
66 * Will be used on create of SvnNodeEntry iff
67 * action is add and source is given.
68 * Will be modified after importing all files
69 * of a revision to NODEACT_ADD (copy which can
70 * not be modeled in ccase) or NODEACT_MOVE
72 #define NODEACT_COPY_OR_MOVE 3
74 /**
75 * node was deleted
77 #define NODEACT_DELETE 2
79 /**
80 * Node was added or copied from other location
82 #define NODEACT_ADD 1
84 /**
85 * node was modified
87 #define NODEACT_CHANGE 0
89 /**
90 * unknown action
92 #define NODEACT_UNKNOWN -1
94 /**
95 * Node is a directory
97 #define NODEKIND_DIR 1
99 /**
100 * Node is a file
102 #define NODEKIND_FILE 0
105 * unknown type of node
107 #define NODEKIND_UNKNOWN -1
109 static char line_buffer[10000];
110 static int line_buffer_len = 0;
111 static int line_len = 0;
114 * read string up to newline from input stream
115 * return all characters except the newline
117 static char *svndump_read_line(void)
119 char *res;
120 char *end;
121 int n_read;
123 if (line_len) {
124 memmove(line_buffer, &line_buffer[line_len],
125 line_buffer_len - line_len);
126 line_buffer_len -= line_len;
127 line_len = 0;
130 end = memchr(line_buffer, '\n', line_buffer_len);
131 while (line_buffer_len < 9999 && !feof(stdin) && NULL == end) {
132 n_read =
133 fread(&line_buffer[line_buffer_len], 1, 9999 - line_buffer_len,
134 stdin);
135 end = memchr(&line_buffer[line_buffer_len], '\n', n_read);
136 line_buffer_len += n_read;
139 if (ferror(stdin))
140 return NULL;
142 if (end != NULL) {
143 line_len = end - line_buffer;
144 line_buffer[line_len++] = '\0';
145 } else {
146 line_len = line_buffer_len;
147 line_buffer[line_buffer_len] = '\0';
150 if (line_len == 0)
151 return NULL;
153 return line_buffer;
157 * so a line can be pushed-back after read
159 static void svndump_pushBackInputLine()
161 if (line_len) {
162 if (line_buffer[line_len - 1] == '\0')
163 line_buffer[line_len - 1] = '\n';
164 line_buffer[line_buffer_len] = '\0';
165 line_len = 0;
169 static char *svndump_read_string(int len)
171 char *s = malloc(len + 1);
172 int offset = 0;
173 if (line_buffer_len > line_len) {
174 offset = line_buffer_len - line_len;
175 if (offset > len)
176 offset = len;
177 memcpy(s, &line_buffer[line_len], offset);
178 line_len += offset;
180 while (offset < len && !feof(stdin)) {
181 offset += fread(&s[offset], 1, len - offset, stdin);
183 s[offset] = '\0';
184 return s;
187 char byte_buffer[4096];
188 static void copy_bytes(int len)
190 int in, out;
191 if (line_buffer_len > line_len) {
192 in = line_buffer_len - line_len;
193 if (in > len)
194 in = len;
195 out = 0;
196 while (out < in && !ferror(stdout)) {
197 out +=
198 fwrite(&line_buffer[line_len + out], 1, in - out, stdout);
200 len -= in;
201 line_len += in;
203 while (len > 0 && !feof(stdin)) {
204 in = len < 4096 ? len : 4096;
205 in = fread(byte_buffer, 1, in, stdin);
206 len -= in;
207 out = 0;
208 while (out < in && !ferror(stdout)) {
209 out += fwrite(&byte_buffer[out], 1, in - out, stdout);
214 static void skip_bytes(int len)
216 int in;
217 if (line_buffer_len > line_len) {
218 in = line_buffer_len - line_len;
219 if (in > len)
220 in = len;
221 line_len += in;
222 len -= in;
224 while (len > 0 && !feof(stdin)) {
225 in = len < 4096 ? len : 4096;
226 in = fread(byte_buffer, 1, in, stdin);
227 len -= in;
231 static int strendswith(char *s, char *end)
233 int end_len = strlen(end);
234 int s_len = strlen(s);
235 return s_len >= end_len && !strcmp(&s[s_len - end_len], end);
238 static uint32_t next_blob_mark(void)
240 static int32_t mark = 1000000000;
241 return mark++;
245 * read a modified file (node) within a revision
247 static void svnnode_read(char *fname)
249 int type = NODEKIND_UNKNOWN;
250 int action = NODEACT_UNKNOWN;
251 int propLength = 0;
252 int textLength = 0;
253 char *src = NULL;
254 int srcRev = 0;
255 char *dst = strdup(fname);
256 char *t;
257 char *val;
258 uint32_t mark = 0;;
260 fprintf(stderr, "Node path: %s\n", fname);
262 for (t = svndump_read_line();
263 t && *t;
264 t = svndump_read_line()) {
265 if (!strncmp(t, "Node-kind:", 10)) {
266 val = &t[11];
267 if (!strncasecmp(val, "dir", 3))
268 type = NODEKIND_DIR;
270 else if (!strncasecmp(val, "file", 4))
271 type = NODEKIND_FILE;
273 else
274 type = NODEKIND_UNKNOWN;
275 } else if (!strncmp(t, "Node-action", 11)) {
276 val = &t[13];
277 if (!strncasecmp(val, "delete", 6))
278 action = NODEACT_DELETE;
280 else if (!strncasecmp(val, "add", 3))
281 action = NODEACT_ADD;
283 else if (!strncasecmp(val, "change", 6))
284 action = NODEACT_CHANGE;
286 else
287 action = NODEACT_UNKNOWN;
288 } else if (!strncmp(t, "Node-copyfrom-path", 18)) {
289 src = strdup(&t[20]);
290 fprintf(stderr, "Node copy path: %s\n", src);
291 } else if (!strncmp(t, "Node-copyfrom-rev", 17)) {
292 val = &t[19];
293 srcRev = atoi(val);
294 fprintf(stderr, "Node copy revision: %d\n", srcRev);
295 } else if (!strncmp(t, "Text-content-length:", 20)) {
296 val = &t[21];
297 textLength = atoi(val);
298 fprintf(stderr, "Text content length: %d\n", textLength);
299 } else if (!strncmp(t, "Prop-content-length:", 20)) {
300 val = &t[21];
301 propLength = atoi(val);
302 fprintf(stderr, "Prop content length: %d\n", propLength);
306 if (propLength) {
307 skip_bytes(propLength);
309 if (textLength) {
310 mark = next_blob_mark();
311 printf("blob\nmark :%d\ndata %d\n", mark, textLength);
312 copy_bytes(textLength);
313 fputc('\n', stdout);
316 if (action == NODEACT_DELETE) {
317 repo_delete(dst);
318 } else if (action == NODEACT_CHANGE) {
319 if (mark) {
320 repo_modify(dst, mark);
321 } else if (src && srcRev) {
322 repo_copy(srcRev, src, dst);
324 } else if (action == NODEACT_ADD) {
325 if (mark) {
326 repo_add(dst,
327 type == NODEKIND_DIR ? REPO_MODE_DIR : REPO_MODE_BLB,
328 mark);
329 } else if (src) {
330 repo_copy(srcRev, src, dst);
336 * create revision reading from stdin
337 * param number revision number
339 static void svnrev_read(uint32_t number)
341 struct tm tm;
342 time_t timestamp;
343 char *descr = "";
344 char *author = "nobody";
345 char *date = "now";
346 char *t;
347 int len;
348 char *key = "";
349 char *val = "";
351 fprintf(stderr, "Revision: %d\n", number);
353 for (t = svndump_read_line();
354 t && strncasecmp(t, "PROPS-END", 9);
355 t = svndump_read_line()) {
356 if (!strncmp(t, "K ", 2)) {
357 len = atoi(&t[2]);
358 key = svndump_read_string(len);
359 svndump_read_line();
360 } else if (!strncmp(t, "V ", 2)) {
361 len = atoi(&t[2]);
362 val = svndump_read_string(len);
363 if (strendswith(key, ":log")) {
364 descr = val;
365 fprintf(stderr, "Log: %s\n", descr);
366 } else if (strendswith(key, ":author")) {
367 author = val;
368 fprintf(stderr, "Author: %s\n", author);
369 } else if (strendswith(key, ":date")) {
370 date = val;
371 fprintf(stderr, "Date: %s\n", date);
372 strptime(date, "%FT%T", &tm);
373 timestamp = mktime(&tm);
375 key = "";
376 svndump_read_line();
380 for ( ;
381 t && strncmp(t, "Revision-number:", 16);
382 t = svndump_read_line()) {
383 if (!strncmp(t, "Node-path:", 10)) {
384 svnnode_read(&t[11]);
387 if (t)
388 svndump_pushBackInputLine();
390 repo_commit(number);
392 if (!number)
393 return;
395 printf("commit refs/heads/master\nmark :%d\n", number);
396 printf("committer %s <%s@local> %d +0000\n",
397 author, author, time(&timestamp));
398 printf("data %d\n%s\n", strlen(descr), descr);
399 repo_diff(number - 1, number);
400 fputc('\n', stdout);
402 printf("progress Imported commit %d.\n\n", number);
406 * create dump representation by importing dump file
408 static void svndump_read(void)
410 char *t;
411 for (t = svndump_read_line(); t; t = svndump_read_line()) {
412 if (!strncmp(t, "Revision-number:", 16)) {
413 svnrev_read(atoi(&t[17]));
418 int main(int argc, char **argv)
420 svndump_read();
421 return 0;