Add pool_tok_seq() to string_pool.c
[svn-fe.git] / svndump.c
blob97cc6ebe3abd6b23c6e9bae910bb90a032c52594
1 /*
2 * Parse and rearrange a svnadmin dump.
3 * Create the dump with:
4 * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
5 */
7 #define _GNU_SOURCE
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <time.h>
13 #include "repo_tree.h"
14 #include "fast_export.h"
15 #include "line_buffer.h"
17 #define NODEACT_REPLACE 4
18 #define NODEACT_DELETE 3
19 #define NODEACT_ADD 2
20 #define NODEACT_CHANGE 1
21 #define NODEACT_UNKNOWN 0
23 #define DUMP_CTX 0
24 #define REV_CTX 1
25 #define NODE_CTX 2
27 #define LENGTH_UNKNOWN (~0)
29 #define BLOB_MARK_OFFSET 1000000000
31 static struct {
32 uint32_t action, propLength, textLength, srcRev, srcMode, mark, type;
33 char *src, *dst;
34 } node_ctx;
36 static struct {
37 uint32_t revision;
38 time_t timestamp;
39 char *descr, *author, *date;
40 } rev_ctx;
42 static struct {
43 char *uuid, *url;
44 } dump_ctx;
46 static void reset_node_ctx(char *fname)
48 node_ctx.type = 0;
49 node_ctx.action = NODEACT_UNKNOWN;
50 node_ctx.propLength = LENGTH_UNKNOWN;
51 node_ctx.textLength = LENGTH_UNKNOWN;
52 if (node_ctx.src)
53 free(node_ctx.src);
54 node_ctx.src = NULL;
55 node_ctx.srcRev = 0;
56 node_ctx.srcMode = 0;
57 if (node_ctx.dst)
58 free(node_ctx.dst);
59 node_ctx.dst = fname;
60 node_ctx.mark = 0;
63 static void reset_rev_ctx(uint32_t revision)
65 rev_ctx.revision = revision;
66 rev_ctx.timestamp = 0;
67 if (rev_ctx.descr)
68 free(rev_ctx.descr);
69 rev_ctx.descr = NULL;
70 if (rev_ctx.author)
71 free(rev_ctx.author);
72 rev_ctx.author = NULL;
73 if (rev_ctx.date)
74 free(rev_ctx.date);
75 rev_ctx.date = NULL;
78 static void reset_dump_ctx(char *url)
80 if (dump_ctx.url)
81 free(dump_ctx.url);
82 dump_ctx.url = url;
83 if (dump_ctx.uuid)
84 free(dump_ctx.uuid);
85 dump_ctx.uuid = NULL;
88 static uint32_t next_blob_mark(void)
90 static uint32_t mark = BLOB_MARK_OFFSET;
91 return mark++;
94 static void read_props(void)
96 struct tm tm;
97 uint32_t len;
98 char *key = NULL;
99 char *val = NULL;
100 char *t;
101 while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
102 if (!strncmp(t, "K ", 2)) {
103 len = atoi(&t[2]);
104 key = buffer_read_string(len);
105 buffer_read_line();
106 } else if (!strncmp(t, "V ", 2)) {
107 len = atoi(&t[2]);
108 val = buffer_read_string(len);
109 if (!strcmp(key, "svn:log")) {
110 if (rev_ctx.descr)
111 free(rev_ctx.descr);
112 rev_ctx.descr = val;
113 } else if (!strcmp(key, "svn:author")) {
114 if (rev_ctx.author)
115 free(rev_ctx.author);
116 rev_ctx.author = val;
117 } else if (!strcmp(key, "svn:date")) {
118 if (rev_ctx.date)
119 free(rev_ctx.date);
120 rev_ctx.date = val;
121 strptime(rev_ctx.date, "%FT%T", &tm);
122 timezone = 0;
123 tm.tm_isdst = 0;
124 rev_ctx.timestamp = mktime(&tm);
125 } else if (!strcmp(key, "svn:executable")) {
126 if (node_ctx.type == REPO_MODE_BLB) {
127 node_ctx.type = REPO_MODE_EXE;
129 free(val);
130 } else if (!strcmp(key, "svn:special")) {
131 if (node_ctx.type == REPO_MODE_BLB) {
132 node_ctx.type = REPO_MODE_LNK;
134 free(val);
135 } else {
136 free(val);
138 if (key)
139 free(key);
140 key = NULL;
141 buffer_read_line();
146 static void handle_node(void)
148 if (node_ctx.propLength != LENGTH_UNKNOWN && node_ctx.propLength) {
149 read_props();
152 if (node_ctx.src && node_ctx.srcRev) {
153 node_ctx.srcMode =
154 repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
157 if (node_ctx.textLength != LENGTH_UNKNOWN &&
158 node_ctx.type != REPO_MODE_DIR) {
159 node_ctx.mark = next_blob_mark();
162 if (node_ctx.action == NODEACT_DELETE) {
163 repo_delete(node_ctx.dst);
164 } else if (node_ctx.action == NODEACT_CHANGE ||
165 node_ctx.action == NODEACT_REPLACE) {
166 if (node_ctx.propLength != LENGTH_UNKNOWN &&
167 node_ctx.textLength != LENGTH_UNKNOWN) {
168 repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark);
169 } else if (node_ctx.textLength != LENGTH_UNKNOWN) {
170 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
172 } else if (node_ctx.action == NODEACT_ADD) {
173 if (node_ctx.src && node_ctx.srcRev &&
174 node_ctx.propLength == LENGTH_UNKNOWN &&
175 node_ctx.textLength != LENGTH_UNKNOWN) {
176 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
177 } else if (node_ctx.type == REPO_MODE_DIR ||
178 node_ctx.textLength != LENGTH_UNKNOWN){
179 repo_add(node_ctx.dst, node_ctx.type, node_ctx.mark);
183 if (node_ctx.propLength == LENGTH_UNKNOWN && node_ctx.srcMode) {
184 node_ctx.type = node_ctx.srcMode;
187 if (node_ctx.mark) {
188 fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
189 } else if (node_ctx.textLength != LENGTH_UNKNOWN) {
190 buffer_skip_bytes(node_ctx.textLength);
194 static void handle_revision(void)
196 repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.descr, dump_ctx.uuid,
197 dump_ctx.url, rev_ctx.timestamp);
200 static void svndump_read(char *url)
202 char *val;
203 char *t;
204 uint32_t active_ctx = DUMP_CTX;
205 uint32_t len;
207 reset_dump_ctx(url);
208 while ((t = buffer_read_line())) {
209 val = strstr(t, ": ");
210 if (!val) continue;
211 *val++ = '\0';
212 *val++ = '\0';
214 if(!strcmp(t, "UUID")) {
215 dump_ctx.uuid = strdup(val);
216 } else if (!strcmp(t, "Revision-number")) {
217 if (active_ctx != DUMP_CTX) handle_revision();
218 active_ctx = REV_CTX;
219 reset_rev_ctx(atoi(val));
220 } else if (!strcmp(t, "Node-path")) {
221 active_ctx = NODE_CTX;
222 reset_node_ctx(strdup(val));
223 } else if (!strcmp(t, "Node-kind")) {
224 if (!strcmp(val, "dir")) {
225 node_ctx.type = REPO_MODE_DIR;
226 } else if (!strcmp(val, "file")) {
227 node_ctx.type = REPO_MODE_BLB;
228 } else {
229 fprintf(stderr, "Unknown node-kind: %s\n", val);
231 } else if (!strcmp(t, "Node-action")) {
232 if (!strcmp(val, "delete")) {
233 node_ctx.action = NODEACT_DELETE;
234 } else if (!strcmp(val, "add")) {
235 node_ctx.action = NODEACT_ADD;
236 } else if (!strcmp(val, "change")) {
237 node_ctx.action = NODEACT_CHANGE;
238 } else if (!strcmp(val, "replace")) {
239 node_ctx.action = NODEACT_REPLACE;
240 } else {
241 fprintf(stderr, "Unknown node-action: %s\n", val);
242 node_ctx.action = NODEACT_UNKNOWN;
244 } else if (!strcmp(t, "Node-copyfrom-path")) {
245 if (node_ctx.src)
246 free(node_ctx.src);
247 node_ctx.src = strdup(val);
248 } else if (!strcmp(t, "Node-copyfrom-rev")) {
249 node_ctx.srcRev = atoi(val);
250 } else if (!strcmp(t, "Text-content-length")) {
251 node_ctx.textLength = atoi(val);
252 } else if (!strcmp(t, "Prop-content-length")) {
253 node_ctx.propLength = atoi(val);
254 } else if (!strcmp(t, "Content-length")) {
255 len = atoi(val);
256 buffer_read_line();
257 if (active_ctx == REV_CTX) {
258 read_props();
259 } else if (active_ctx == NODE_CTX) {
260 handle_node();
261 active_ctx = REV_CTX;
262 } else {
263 fprintf(stderr, "Unexpected content length header: %d\n", len);
264 buffer_skip_bytes(len);
268 if (active_ctx != DUMP_CTX) handle_revision();
271 static void svndump_reset(void)
273 repo_reset();
274 reset_dump_ctx(NULL);
275 reset_rev_ctx(0);
276 reset_node_ctx(NULL);
279 int main(int argc, char **argv)
281 svndump_read((argc > 1) ? argv[1] : NULL);
282 svndump_reset();
283 return 0;