Resolved memory haemorrhage in perl replay implementation.
[svn-fe.git] / svndump.c
blob25a21d15cf5dcb4ebc9c47763c61a231944323ad
1 /*
2 * Parse and rearrange a svnadmin dump.
3 * Create the dump with:
4 * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
5 */
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
11 #include "repo_tree.h"
12 #include "fast_export.h"
13 #include "line_buffer.h"
15 #define NODEACT_REPLACE 4
16 #define NODEACT_DELETE 3
17 #define NODEACT_ADD 2
18 #define NODEACT_CHANGE 1
19 #define NODEACT_UNKNOWN 0
21 #define DUMP_CTX 0
22 #define REV_CTX 1
23 #define NODE_CTX 2
25 #define LENGTH_UNKNOWN (~0)
27 #define BLOB_MARK_OFFSET 1000000000
29 static struct {
30 uint32_t action, propLength, textLength, srcRev, srcMode, mark, type;
31 char *src, *dst;
32 } node_ctx;
34 static struct {
35 uint32_t revision;
36 time_t timestamp;
37 char *descr, *author, *date;
38 } rev_ctx;
40 static struct {
41 char *uuid, *url;
42 } dump_ctx;
44 static void reset_node_ctx(char * fname)
46 node_ctx.type = 0;
47 node_ctx.action = NODEACT_UNKNOWN;
48 node_ctx.propLength = LENGTH_UNKNOWN;
49 node_ctx.textLength = LENGTH_UNKNOWN;
50 node_ctx.src = NULL;
51 node_ctx.srcRev = 0;
52 node_ctx.srcMode = 0;
53 node_ctx.dst = strdup(fname);
54 node_ctx.mark = 0;
57 static void reset_rev_ctx(uint32_t revision)
59 rev_ctx.revision = revision;
60 rev_ctx.timestamp = 0;
61 rev_ctx.descr = "";
62 rev_ctx.author = "nobody";
63 rev_ctx.date = "now";
66 static void reset_dump_ctx(char * url) {
67 dump_ctx.url = url;
68 dump_ctx.uuid = NULL;
71 static uint32_t next_blob_mark(void)
73 static uint32_t mark = BLOB_MARK_OFFSET;
74 return mark++;
77 static void read_props(void)
79 struct tm tm;
80 uint32_t len;
81 char *key = "";
82 char *val = "";
83 char *t;
84 while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
85 if (!strncmp(t, "K ", 2)) {
86 len = atoi(&t[2]);
87 key = buffer_read_string(len);
88 buffer_read_line();
89 } else if (!strncmp(t, "V ", 2)) {
90 len = atoi(&t[2]);
91 val = buffer_read_string(len);
92 if (!strcmp(key, "svn:log")) {
93 rev_ctx.descr = val;
94 } else if (!strcmp(key, "svn:author")) {
95 rev_ctx.author = val;
96 } else if (!strcmp(key, "svn:date")) {
97 rev_ctx.date = val;
98 strptime(rev_ctx.date, "%FT%T", &tm);
99 timezone = 0;
100 tm.tm_isdst = 0;
101 rev_ctx.timestamp = mktime(&tm);
102 } else if (!strcmp(key, "svn:executable")) {
103 if (node_ctx.type == REPO_MODE_BLB) {
104 node_ctx.type = REPO_MODE_EXE;
106 } else if (!strcmp(key, "svn:special")) {
107 if (node_ctx.type == REPO_MODE_BLB) {
108 node_ctx.type = REPO_MODE_LNK;
111 key = "";
112 buffer_read_line();
117 static void handle_node(void)
119 if (node_ctx.propLength != LENGTH_UNKNOWN && node_ctx.propLength) {
120 read_props();
123 if (node_ctx.src && node_ctx.srcRev) {
124 node_ctx.srcMode =
125 repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
128 if (node_ctx.textLength != LENGTH_UNKNOWN &&
129 node_ctx.type != REPO_MODE_DIR) {
130 node_ctx.mark = next_blob_mark();
133 if (node_ctx.action == NODEACT_DELETE) {
134 repo_delete(node_ctx.dst);
135 } else if (node_ctx.action == NODEACT_CHANGE ||
136 node_ctx.action == NODEACT_REPLACE) {
137 if (node_ctx.propLength != LENGTH_UNKNOWN &&
138 node_ctx.textLength != LENGTH_UNKNOWN) {
139 repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark);
140 } else if (node_ctx.textLength >= 0) {
141 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
143 } else if (node_ctx.action == NODEACT_ADD) {
144 if (node_ctx.src && node_ctx.srcRev &&
145 node_ctx.propLength == LENGTH_UNKNOWN &&
146 node_ctx.textLength != LENGTH_UNKNOWN) {
147 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
148 } else if (node_ctx.type == REPO_MODE_DIR ||
149 node_ctx.textLength != LENGTH_UNKNOWN){
150 repo_add(node_ctx.dst, node_ctx.type, node_ctx.mark);
154 if (node_ctx.propLength == LENGTH_UNKNOWN && node_ctx.srcMode) {
155 node_ctx.type = node_ctx.srcMode;
158 if (node_ctx.mark) {
159 fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
160 } else if (node_ctx.textLength != LENGTH_UNKNOWN) {
161 buffer_skip_bytes(node_ctx.textLength);
165 static void handle_revision(void)
167 repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.descr, dump_ctx.uuid,
168 dump_ctx.url, rev_ctx.timestamp);
171 static void svndump_read(char * url)
173 char *val;
174 char *t;
175 uint32_t active_ctx = DUMP_CTX;
176 uint32_t len;
178 reset_dump_ctx(url);
179 while ((t = buffer_read_line())) {
180 val = strstr(t, ": ");
181 if (!val) continue;
182 *val++ = '\0';
183 *val++ = '\0';
185 if(!strcmp(t, "UUID")) {
186 dump_ctx.uuid = strdup(val);
187 } else if (!strcmp(t, "Revision-number")) {
188 if (active_ctx != DUMP_CTX) handle_revision();
189 active_ctx = REV_CTX;
190 reset_rev_ctx(atoi(val));
191 } else if (!strcmp(t, "Node-path")) {
192 active_ctx = NODE_CTX;
193 reset_node_ctx(val);
194 } else if (!strcmp(t, "Node-kind")) {
195 if (!strcmp(val, "dir")) {
196 node_ctx.type = REPO_MODE_DIR;
197 } else if (!strcmp(val, "file")) {
198 node_ctx.type = REPO_MODE_BLB;
199 } else {
200 fprintf(stderr, "Unknown node-kind: %s\n", val);
202 } else if (!strcmp(t, "Node-action")) {
203 if (!strcmp(val, "delete")) {
204 node_ctx.action = NODEACT_DELETE;
205 } else if (!strcmp(val, "add")) {
206 node_ctx.action = NODEACT_ADD;
207 } else if (!strcmp(val, "change")) {
208 node_ctx.action = NODEACT_CHANGE;
209 } else if (!strcmp(val, "replace")) {
210 node_ctx.action = NODEACT_REPLACE;
211 } else {
212 fprintf(stderr, "Unknown node-action: %s\n", val);
213 node_ctx.action = NODEACT_UNKNOWN;
215 } else if (!strcmp(t, "Node-copyfrom-path")) {
216 node_ctx.src = strdup(val);
217 } else if (!strcmp(t, "Node-copyfrom-rev")) {
218 node_ctx.srcRev = atoi(val);
219 } else if (!strcmp(t, "Text-content-length")) {
220 node_ctx.textLength = atoi(val);
221 } else if (!strcmp(t, "Prop-content-length")) {
222 node_ctx.propLength = atoi(val);
223 } else if (!strcmp(t, "Content-length")) {
224 len = atoi(val);
225 buffer_read_line();
226 if (active_ctx == REV_CTX) {
227 read_props();
228 } else if (active_ctx == NODE_CTX) {
229 handle_node();
230 active_ctx = REV_CTX;
231 } else {
232 fprintf(stderr, "Unexpected content length header: %d\n", len);
233 buffer_skip_bytes(len);
237 if (active_ctx != DUMP_CTX) handle_revision();
240 int main(int argc, char **argv)
242 svndump_read((argc > 1) ? argv[1] : NULL);
243 return 0;