2 * Parse and rearrange a svnadmin dump.
3 * Create the dump with:
4 * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
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
18 #define NODEACT_CHANGE 1
19 #define NODEACT_UNKNOWN 0
25 #define LENGTH_UNKNOWN (~0)
27 #define BLOB_MARK_OFFSET 1000000000
30 uint32_t action
, propLength
, textLength
, srcRev
, srcMode
, mark
, type
;
37 char *descr
, *author
, *date
;
44 static void reset_node_ctx(char * fname
)
47 node_ctx
.action
= NODEACT_UNKNOWN
;
48 node_ctx
.propLength
= LENGTH_UNKNOWN
;
49 node_ctx
.textLength
= LENGTH_UNKNOWN
;
53 node_ctx
.dst
= strdup(fname
);
57 static void reset_rev_ctx(uint32_t revision
)
59 rev_ctx
.revision
= revision
;
60 rev_ctx
.timestamp
= 0;
62 rev_ctx
.author
= "nobody";
66 static void reset_dump_ctx(char * url
) {
71 static uint32_t next_blob_mark(void)
73 static uint32_t mark
= BLOB_MARK_OFFSET
;
77 static void read_props(void)
84 while ((t
= buffer_read_line()) && strcmp(t
, "PROPS-END")) {
85 if (!strncmp(t
, "K ", 2)) {
87 key
= buffer_read_string(len
);
89 } else if (!strncmp(t
, "V ", 2)) {
91 val
= buffer_read_string(len
);
92 if (!strcmp(key
, "svn:log")) {
94 } else if (!strcmp(key
, "svn:author")) {
96 } else if (!strcmp(key
, "svn:date")) {
98 strptime(rev_ctx
.date
, "%FT%T", &tm
);
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
;
117 static void handle_node(void)
119 if (node_ctx
.propLength
!= LENGTH_UNKNOWN
&& node_ctx
.propLength
) {
123 if (node_ctx
.src
&& node_ctx
.srcRev
) {
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
;
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
)
175 uint32_t active_ctx
= DUMP_CTX
;
179 while ((t
= buffer_read_line())) {
180 val
= strstr(t
, ": ");
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
;
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
;
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
;
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")) {
226 if (active_ctx
== REV_CTX
) {
228 } else if (active_ctx
== NODE_CTX
) {
230 active_ctx
= REV_CTX
;
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
);