Add character pool to line_buffer.c
[svn-fe.git] / svndump.c
blobd36d0074269ae4d0b49a74f947405db82cf9d269
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"
16 #include "obj_pool.h"
17 #include "string_pool.h"
19 #define NODEACT_REPLACE 4
20 #define NODEACT_DELETE 3
21 #define NODEACT_ADD 2
22 #define NODEACT_CHANGE 1
23 #define NODEACT_UNKNOWN 0
25 #define DUMP_CTX 0
26 #define REV_CTX 1
27 #define NODE_CTX 2
29 #define LENGTH_UNKNOWN (~0)
31 #define BLOB_MARK_OFFSET 1000000000
33 /* Create memory pool for log messages */
34 obj_pool_gen(log, char, 4096);
36 static char* log_copy(uint32_t length, char *log)
38 char *buffer;
39 log_free(log_pool.size);
40 buffer = log_pointer(log_alloc(length));
41 strncpy(buffer, log, length);
42 return buffer;
45 static struct {
46 uint32_t action, propLength, textLength, srcRev, srcMode, mark, type;
47 char *src, *dst;
48 } node_ctx;
50 static struct {
51 uint32_t revision;
52 time_t timestamp;
53 char *log, *author;
54 } rev_ctx;
56 static struct {
57 char *uuid, *url;
58 } dump_ctx;
60 static void reset_node_ctx(char *fname)
62 node_ctx.type = 0;
63 node_ctx.action = NODEACT_UNKNOWN;
64 node_ctx.propLength = LENGTH_UNKNOWN;
65 node_ctx.textLength = LENGTH_UNKNOWN;
66 if (node_ctx.src)
67 free(node_ctx.src);
68 node_ctx.src = NULL;
69 node_ctx.srcRev = 0;
70 node_ctx.srcMode = 0;
71 if (node_ctx.dst)
72 free(node_ctx.dst);
73 node_ctx.dst = fname;
74 node_ctx.mark = 0;
77 static void reset_rev_ctx(uint32_t revision)
79 rev_ctx.revision = revision;
80 rev_ctx.timestamp = 0;
81 rev_ctx.log = NULL;
82 if (rev_ctx.author)
83 free(rev_ctx.author);
84 rev_ctx.author = NULL;
87 static void reset_dump_ctx(char *url)
89 if (dump_ctx.url)
90 free(dump_ctx.url);
91 dump_ctx.url = url;
92 if (dump_ctx.uuid)
93 free(dump_ctx.uuid);
94 dump_ctx.uuid = NULL;
97 static uint32_t next_blob_mark(void)
99 static uint32_t mark = BLOB_MARK_OFFSET;
100 return mark++;
103 static void read_props(void)
105 struct tm tm;
106 uint32_t len;
107 uint32_t key = ~0;
108 char *val = NULL;
109 char *t;
110 while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
111 if (!strncmp(t, "K ", 2)) {
112 len = atoi(&t[2]);
113 key = pool_intern(buffer_read_string(len));
114 buffer_read_line();
115 } else if (!strncmp(t, "V ", 2)) {
116 len = atoi(&t[2]);
117 val = buffer_read_string(len);
118 if (key == pool_intern("svn:log")) {
119 rev_ctx.log = log_copy(len, val);
120 } else if (key == pool_intern("svn:author")) {
121 if (rev_ctx.author)
122 free(rev_ctx.author);
123 rev_ctx.author = strdup(val);
124 } else if (key == pool_intern("svn:date")) {
125 strptime(val, "%FT%T", &tm);
126 timezone = 0;
127 tm.tm_isdst = 0;
128 rev_ctx.timestamp = mktime(&tm);
129 } else if (key == pool_intern("svn:executable")) {
130 if (node_ctx.type == REPO_MODE_BLB) {
131 node_ctx.type = REPO_MODE_EXE;
133 } else if (key == pool_intern("svn:special")) {
134 if (node_ctx.type == REPO_MODE_BLB) {
135 node_ctx.type = REPO_MODE_LNK;
138 key = ~0;
139 buffer_read_line();
144 static void handle_node(void)
146 if (node_ctx.propLength != LENGTH_UNKNOWN && node_ctx.propLength) {
147 read_props();
150 if (node_ctx.src && node_ctx.srcRev) {
151 node_ctx.srcMode =
152 repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
155 if (node_ctx.textLength != LENGTH_UNKNOWN &&
156 node_ctx.type != REPO_MODE_DIR) {
157 node_ctx.mark = next_blob_mark();
160 if (node_ctx.action == NODEACT_DELETE) {
161 repo_delete(node_ctx.dst);
162 } else if (node_ctx.action == NODEACT_CHANGE ||
163 node_ctx.action == NODEACT_REPLACE) {
164 if (node_ctx.propLength != LENGTH_UNKNOWN &&
165 node_ctx.textLength != LENGTH_UNKNOWN) {
166 repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark);
167 } else if (node_ctx.textLength != LENGTH_UNKNOWN) {
168 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
170 } else if (node_ctx.action == NODEACT_ADD) {
171 if (node_ctx.src && node_ctx.srcRev &&
172 node_ctx.propLength == LENGTH_UNKNOWN &&
173 node_ctx.textLength != LENGTH_UNKNOWN) {
174 node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
175 } else if (node_ctx.type == REPO_MODE_DIR ||
176 node_ctx.textLength != LENGTH_UNKNOWN){
177 repo_add(node_ctx.dst, node_ctx.type, node_ctx.mark);
181 if (node_ctx.propLength == LENGTH_UNKNOWN && node_ctx.srcMode) {
182 node_ctx.type = node_ctx.srcMode;
185 if (node_ctx.mark) {
186 fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
187 } else if (node_ctx.textLength != LENGTH_UNKNOWN) {
188 buffer_skip_bytes(node_ctx.textLength);
192 static void handle_revision(void)
194 repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log, dump_ctx.uuid,
195 dump_ctx.url, rev_ctx.timestamp);
198 static void svndump_read(char *url)
200 char *val;
201 char *t;
202 uint32_t active_ctx = DUMP_CTX;
203 uint32_t len;
205 reset_dump_ctx(url);
206 while ((t = buffer_read_line())) {
207 val = strstr(t, ": ");
208 if (!val) continue;
209 *val++ = '\0';
210 *val++ = '\0';
212 if(!strcmp(t, "UUID")) {
213 dump_ctx.uuid = strdup(val);
214 } else if (!strcmp(t, "Revision-number")) {
215 if (active_ctx != DUMP_CTX) handle_revision();
216 active_ctx = REV_CTX;
217 reset_rev_ctx(atoi(val));
218 } else if (!strcmp(t, "Node-path")) {
219 active_ctx = NODE_CTX;
220 reset_node_ctx(strdup(val));
221 } else if (!strcmp(t, "Node-kind")) {
222 if (!strcmp(val, "dir")) {
223 node_ctx.type = REPO_MODE_DIR;
224 } else if (!strcmp(val, "file")) {
225 node_ctx.type = REPO_MODE_BLB;
226 } else {
227 fprintf(stderr, "Unknown node-kind: %s\n", val);
229 } else if (!strcmp(t, "Node-action")) {
230 if (!strcmp(val, "delete")) {
231 node_ctx.action = NODEACT_DELETE;
232 } else if (!strcmp(val, "add")) {
233 node_ctx.action = NODEACT_ADD;
234 } else if (!strcmp(val, "change")) {
235 node_ctx.action = NODEACT_CHANGE;
236 } else if (!strcmp(val, "replace")) {
237 node_ctx.action = NODEACT_REPLACE;
238 } else {
239 fprintf(stderr, "Unknown node-action: %s\n", val);
240 node_ctx.action = NODEACT_UNKNOWN;
242 } else if (!strcmp(t, "Node-copyfrom-path")) {
243 if (node_ctx.src)
244 free(node_ctx.src);
245 node_ctx.src = strdup(val);
246 } else if (!strcmp(t, "Node-copyfrom-rev")) {
247 node_ctx.srcRev = atoi(val);
248 } else if (!strcmp(t, "Text-content-length")) {
249 node_ctx.textLength = atoi(val);
250 } else if (!strcmp(t, "Prop-content-length")) {
251 node_ctx.propLength = atoi(val);
252 } else if (!strcmp(t, "Content-length")) {
253 len = atoi(val);
254 buffer_read_line();
255 if (active_ctx == REV_CTX) {
256 read_props();
257 } else if (active_ctx == NODE_CTX) {
258 handle_node();
259 active_ctx = REV_CTX;
260 } else {
261 fprintf(stderr, "Unexpected content length header: %d\n", len);
262 buffer_skip_bytes(len);
266 if (active_ctx != DUMP_CTX) handle_revision();
269 static void svndump_reset(void)
271 log_reset();
272 buffer_reset();
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;