2 * Parse and rearrange a svnadmin dump.
3 * Create the dump with:
4 * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
13 #include "repo_tree.h"
14 #include "fast_export.h"
15 #include "line_buffer.h"
17 #include "string_pool.h"
19 #define NODEACT_REPLACE 4
20 #define NODEACT_DELETE 3
22 #define NODEACT_CHANGE 1
23 #define NODEACT_UNKNOWN 0
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
)
39 log_free(log_pool
.size
);
40 buffer
= log_pointer(log_alloc(length
));
41 strncpy(buffer
, log
, length
);
46 uint32_t action
, propLength
, textLength
, srcRev
, srcMode
, mark
, type
;
60 static void reset_node_ctx(char *fname
)
63 node_ctx
.action
= NODEACT_UNKNOWN
;
64 node_ctx
.propLength
= LENGTH_UNKNOWN
;
65 node_ctx
.textLength
= LENGTH_UNKNOWN
;
77 static void reset_rev_ctx(uint32_t revision
)
79 rev_ctx
.revision
= revision
;
80 rev_ctx
.timestamp
= 0;
84 rev_ctx
.author
= NULL
;
87 static void reset_dump_ctx(char *url
)
97 static uint32_t next_blob_mark(void)
99 static uint32_t mark
= BLOB_MARK_OFFSET
;
103 static void read_props(void)
110 while ((t
= buffer_read_line()) && strcmp(t
, "PROPS-END")) {
111 if (!strncmp(t
, "K ", 2)) {
113 key
= pool_intern(buffer_read_string(len
));
115 } else if (!strncmp(t
, "V ", 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")) {
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
);
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
;
144 static void handle_node(void)
146 if (node_ctx
.propLength
!= LENGTH_UNKNOWN
&& node_ctx
.propLength
) {
150 if (node_ctx
.src
&& node_ctx
.srcRev
) {
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
;
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
)
202 uint32_t active_ctx
= DUMP_CTX
;
206 while ((t
= buffer_read_line())) {
207 val
= strstr(t
, ": ");
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
;
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
;
239 fprintf(stderr
, "Unknown node-action: %s\n", val
);
240 node_ctx
.action
= NODEACT_UNKNOWN
;
242 } else if (!strcmp(t
, "Node-copyfrom-path")) {
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")) {
255 if (active_ctx
== REV_CTX
) {
257 } else if (active_ctx
== NODE_CTX
) {
259 active_ctx
= REV_CTX
;
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)
274 reset_dump_ctx(NULL
);
276 reset_node_ctx(NULL
);
279 int main(int argc
, char **argv
)
281 svndump_read((argc
> 1) ? argv
[1] : NULL
);