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 #define NODEACT_REPLACE 4
18 #define NODEACT_DELETE 3
20 #define NODEACT_CHANGE 1
21 #define NODEACT_UNKNOWN 0
27 #define LENGTH_UNKNOWN (~0)
29 #define BLOB_MARK_OFFSET 1000000000
32 uint32_t action
, propLength
, textLength
, srcRev
, srcMode
, mark
, type
;
39 char *descr
, *author
, *date
;
46 static void reset_node_ctx(char *fname
)
49 node_ctx
.action
= NODEACT_UNKNOWN
;
50 node_ctx
.propLength
= LENGTH_UNKNOWN
;
51 node_ctx
.textLength
= LENGTH_UNKNOWN
;
63 static void reset_rev_ctx(uint32_t revision
)
65 rev_ctx
.revision
= revision
;
66 rev_ctx
.timestamp
= 0;
72 rev_ctx
.author
= NULL
;
78 static void reset_dump_ctx(char *url
)
88 static uint32_t next_blob_mark(void)
90 static uint32_t mark
= BLOB_MARK_OFFSET
;
94 static void read_props(void)
101 while ((t
= buffer_read_line()) && strcmp(t
, "PROPS-END")) {
102 if (!strncmp(t
, "K ", 2)) {
104 key
= buffer_read_string(len
);
106 } else if (!strncmp(t
, "V ", 2)) {
108 val
= buffer_read_string(len
);
109 if (!strcmp(key
, "svn:log")) {
113 } else if (!strcmp(key
, "svn:author")) {
115 free(rev_ctx
.author
);
116 rev_ctx
.author
= val
;
117 } else if (!strcmp(key
, "svn:date")) {
121 strptime(rev_ctx
.date
, "%FT%T", &tm
);
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
;
130 } else if (!strcmp(key
, "svn:special")) {
131 if (node_ctx
.type
== REPO_MODE_BLB
) {
132 node_ctx
.type
= REPO_MODE_LNK
;
146 static void handle_node(void)
148 if (node_ctx
.propLength
!= LENGTH_UNKNOWN
&& node_ctx
.propLength
) {
152 if (node_ctx
.src
&& node_ctx
.srcRev
) {
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
;
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
)
204 uint32_t active_ctx
= DUMP_CTX
;
208 while ((t
= buffer_read_line())) {
209 val
= strstr(t
, ": ");
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
;
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
;
241 fprintf(stderr
, "Unknown node-action: %s\n", val
);
242 node_ctx
.action
= NODEACT_UNKNOWN
;
244 } else if (!strcmp(t
, "Node-copyfrom-path")) {
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")) {
257 if (active_ctx
== REV_CTX
) {
259 } else if (active_ctx
== NODE_CTX
) {
261 active_ctx
= REV_CTX
;
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)
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
);