Finished converting main loop of parser to RFC822.
[svn-fe.git] / svndump.c
blob1259dddae26a38ba66b743b5fe6cb505d2e73672
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>
48 #include "repo_tree.h"
49 #include "line_buffer.h"
51 /* node was replaced */
52 #define NODEACT_REPLACE 3
54 /* node was deleted */
55 #define NODEACT_DELETE 2
57 /* node was added or copied from other location */
58 #define NODEACT_ADD 1
60 /* node was modified */
61 #define NODEACT_CHANGE 0
63 /* unknown action */
64 #define NODEACT_UNKNOWN -1
66 static struct {
67 int32_t action, propLength, textLength;
68 uint32_t srcRev, srcMode, mark, type;
69 char *src, *dst;
70 } node_ctx;
72 static struct {
73 uint32_t revision;
74 time_t timestamp;
75 char *descr, *author, *date;
76 } rev_ctx;
78 static struct {
79 char *uuid, *url;
80 } dump_ctx;
82 static void reset_node_ctx(char * fname)
84 node_ctx.type = 0;
85 node_ctx.action = NODEACT_UNKNOWN;
86 node_ctx.propLength = -1;
87 node_ctx.textLength = -1;
88 node_ctx.src = NULL;
89 node_ctx.srcRev = 0;
90 node_ctx.srcMode = 0;
91 node_ctx.dst = strdup(fname);
92 node_ctx.mark = 0;
95 static void reset_rev_ctx(uint32_t revision)
97 rev_ctx.revision = revision;
98 rev_ctx.timestamp = 0;
99 rev_ctx.descr = "";
100 rev_ctx.author = "nobody";
101 rev_ctx.date = "now";
104 static void reset_dump_ctx(char * url) {
105 dump_ctx.url = url;
106 dump_ctx.uuid = NULL;
109 static uint32_t next_blob_mark(void)
111 static int32_t mark = 1000000000;
112 return mark++;
115 static void read_props(void)
117 struct tm tm;
118 int len;
119 char *key = "";
120 char *val = "";
121 char *t;
122 for (t = buffer_read_line();
123 t && strncasecmp(t, "PROPS-END", 9);
124 t = buffer_read_line()) {
125 if (!strncmp(t, "K ", 2)) {
126 len = atoi(&t[2]);
127 key = buffer_read_string(len);
128 buffer_read_line();
129 } else if (!strncmp(t, "V ", 2)) {
130 len = atoi(&t[2]);
131 val = buffer_read_string(len);
132 if (!strcmp(key, "svn:log")) {
133 rev_ctx.descr = val;
134 fprintf(stderr, "Log: %s\n", rev_ctx.descr);
135 } else if (!strcmp(key, "svn:author")) {
136 rev_ctx.author = val;
137 fprintf(stderr, "Author: %s\n", rev_ctx.author);
138 } else if (!strcmp(key, "svn:date")) {
139 rev_ctx.date = val;
140 fprintf(stderr, "Date: %s\n", rev_ctx.date);
141 strptime(rev_ctx.date, "%FT%T", &tm);
142 timezone = 0;
143 tm.tm_isdst = 0;
144 rev_ctx.timestamp = mktime(&tm);
145 } else if (!strcmp(key, "svn:executable")) {
146 if (node_ctx.type == REPO_MODE_BLB) {
147 node_ctx.type = REPO_MODE_EXE;
149 fprintf(stderr, "Executable: %s\n", val);
150 } else if (!strcmp(key, "svn:special")) {
151 if (node_ctx.type == REPO_MODE_BLB) {
152 node_ctx.type = REPO_MODE_LNK;
154 fprintf(stderr, "Special: %s\n", val);
156 key = "";
157 buffer_read_line();
162 static void handle_node(void)
164 if (node_ctx.propLength > 0) {
165 read_props();
168 if (node_ctx.src && node_ctx.srcRev) {
169 node_ctx.srcMode = repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
172 if (node_ctx.textLength >= 0 && node_ctx.type != REPO_MODE_DIR) {
173 node_ctx.mark = next_blob_mark();
176 if (node_ctx.action == NODEACT_DELETE) {
177 repo_delete(node_ctx.dst);
178 } else if (node_ctx.action == NODEACT_CHANGE ||
179 node_ctx.action == NODEACT_REPLACE) {
180 if (node_ctx.propLength >= 0 && node_ctx.textLength >= 0) {
181 repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark);
182 } else if (node_ctx.textLength >= 0) {
183 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
185 } else if (node_ctx.action == NODEACT_ADD) {
186 if (node_ctx.src && node_ctx.srcRev && node_ctx.propLength < 0 && node_ctx.textLength >= 0) {
187 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
188 } else if(node_ctx.type == REPO_MODE_DIR || node_ctx.textLength >= 0){
189 repo_add(node_ctx.dst, node_ctx.type, node_ctx.mark);
193 if (node_ctx.propLength < 0 && node_ctx.srcMode) {
194 node_ctx.type = node_ctx.srcMode;
197 if (node_ctx.mark) {
198 repo_copy_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
199 } else if (node_ctx.textLength > 0) {
200 buffer_skip_bytes(node_ctx.textLength);
204 static void handle_revision(void)
206 repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.descr, dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
209 #define DUMP_CTX 0
210 #define REV_CTX 1
211 #define NODE_CTX 2
213 /* create dump representation by importing dump file */
214 static void svndump_read(char * url)
216 char *val;
217 char *t;
218 int active_ctx = DUMP_CTX;
219 int len;
221 reset_dump_ctx(url);
222 for (t = buffer_read_line(); t; t = buffer_read_line()) {
223 val = strstr(t, ": ");
224 if (!val) continue;
225 *val++ = '\0';
226 *val++ = '\0';
228 if(!strcmp(t, "UUID")) {
229 dump_ctx.uuid = strdup(val);
230 } else if (!strcmp(t, "Revision-number")) {
231 if (active_ctx != DUMP_CTX) handle_revision();
232 active_ctx = REV_CTX;
233 reset_rev_ctx(atoi(val));
234 fprintf(stderr, "Revision: %d\n", rev_ctx.revision);
235 } else if (!strcmp(t, "Node-path")) {
236 active_ctx = NODE_CTX;
237 reset_node_ctx(val);
238 fprintf(stderr, "Node path: %s\n", node_ctx.dst);
239 } else if (!strcmp(t, "Node-kind")) {
240 if (!strcmp(val, "dir")) {
241 node_ctx.type = REPO_MODE_DIR;
242 } else if (!strcmp(val, "file")) {
243 node_ctx.type = REPO_MODE_BLB;
244 } else {
245 fprintf(stderr, "Unknown node-kind: %s\n", val);
247 } else if (!strcmp(t, "Node-action")) {
248 if (!strcmp(val, "delete")) {
249 node_ctx.action = NODEACT_DELETE;
250 } else if (!strcmp(val, "add")) {
251 node_ctx.action = NODEACT_ADD;
252 } else if (!strcmp(val, "change")) {
253 node_ctx.action = NODEACT_CHANGE;
254 } else if (!strcmp(val, "replace")) {
255 node_ctx.action = NODEACT_REPLACE;
256 } else {
257 node_ctx.action = NODEACT_UNKNOWN;
259 } else if (!strcmp(t, "Node-copyfrom-path")) {
260 node_ctx.src = strdup(val);
261 fprintf(stderr, "Node copy path: %s\n", node_ctx.src);
262 } else if (!strcmp(t, "Node-copyfrom-rev")) {
263 node_ctx.srcRev = atoi(val);
264 fprintf(stderr, "Node copy revision: %d\n", node_ctx.srcRev);
265 } else if (!strcmp(t, "Text-content-length")) {
266 node_ctx.textLength = atoi(val);
267 fprintf(stderr, "Text content length: %d\n", node_ctx.textLength);
268 } else if (!strcmp(t, "Prop-content-length")) {
269 node_ctx.propLength = atoi(val);
270 fprintf(stderr, "Prop content length: %d\n", node_ctx.propLength);
271 } else if (!strcmp(t, "Content-length")) {
272 len = atoi(val);
273 buffer_read_line();
274 if (active_ctx == REV_CTX) {
275 read_props();
276 } else if (active_ctx == NODE_CTX) {
277 handle_node();
278 active_ctx = REV_CTX;
279 } else {
280 fprintf(stderr, "Unexpected content length header!\n");
281 buffer_skip_bytes(len);
285 if (active_ctx != DUMP_CTX) handle_revision();
288 int main(int argc, char **argv)
290 svndump_read((argc > 1) ? argv[1] : NULL);
291 return 0;