@matheusbsbs / matheus-bagliano / commits / 723b7a2789
Fork 0

vcs-svn: eliminate repo_tree structure

Rely on fast-import for information about previous revs. This requires always setting up backward flow of information, even for v2 dumps. On the plus side, it simplifies the code by quite a bit and opens the door to further simplifications. [db: adjusted to support final version of the cat-blob patch] [jn: avoiding hard-coding git's name for the empty tree for portability to other backends] Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: David Barr <david.barr@cordelta.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Jonathan Nieder committed Dec 10, 2010 at 04:00 UTC 723b7a2789d66c1365390cc9b9213e34ab8513d7
7 files changed +184 -340
vcs-svn/fast_export.c
+94 -14
@@ -8,6 +8,7 @@
8 #include "line_buffer.h"
9 #include "repo_tree.h"
10 #include "string_pool.h"
11 +#include "strbuf.h"
12
13 #define MAX_GITSVN_LINE_LEN 4096
14
@@ -31,7 +32,7 @@ void fast_export_reset(void)
32 buffer_reset(&report_buffer);
33 }
34
34 -void fast_export_delete(uint32_t depth, uint32_t *path)
35 +void fast_export_delete(uint32_t depth, const uint32_t *path)
36 {
37 putchar('D');
38 putchar(' ');
@@ -39,22 +40,27 @@ void fast_export_delete(uint32_t depth, uint32_t *path)
40 putchar('\n');
41 }
42
42 -void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
43 - uint32_t mark)
43 +static void fast_export_truncate(uint32_t depth, const uint32_t *path, uint32_t mode)
44 {
45 - /* Mode must be 100644, 100755, 120000, or 160000. */
46 - printf("M %06"PRIo32" :%"PRIu32" ", mode, mark);
47 - pool_print_seq(depth, path, '/', stdout);
48 - putchar('\n');
45 + fast_export_modify(depth, path, mode, "inline");
46 + printf("data 0\n\n");
47 }
48
51 -void fast_export_begin_commit(uint32_t revision)
49 +void fast_export_modify(uint32_t depth, const uint32_t *path, uint32_t mode,
50 + const char *dataref)
51 {
53 - printf("# commit %"PRIu32".\n", revision);
52 + /* Mode must be 100644, 100755, 120000, or 160000. */
53 + if (!dataref) {
54 + fast_export_truncate(depth, path, mode);
55 + return;
56 + }
57 + printf("M %06"PRIo32" %s ", mode, dataref);
58 + pool_print_seq(depth, path, '/', stdout);
59 + putchar('\n');
60 }
61
62 static char gitsvnline[MAX_GITSVN_LINE_LEN];
57 -void fast_export_commit(uint32_t revision, uint32_t author, char *log,
63 +void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,
64 uint32_t uuid, uint32_t url,
65 unsigned long timestamp)
66 {
@@ -81,12 +87,31 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
87 printf("from refs/heads/master^0\n");
88 first_commit_done = 1;
89 }
84 - repo_diff(revision - 1, revision);
85 - fputc('\n', stdout);
90 +}
91
92 +void fast_export_end_commit(uint32_t revision)
93 +{
94 printf("progress Imported commit %"PRIu32".\n\n", revision);
95 }
96
97 +static void ls_from_rev(uint32_t rev, uint32_t depth, const uint32_t *path)
98 +{
99 + /* ls :5 path/to/old/file */
100 + printf("ls :%"PRIu32" ", rev);
101 + pool_print_seq(depth, path, '/', stdout);
102 + putchar('\n');
103 + fflush(stdout);
104 +}
105 +
106 +static void ls_from_active_commit(uint32_t depth, const uint32_t *path)
107 +{
108 + /* ls "path/to/file" */
109 + printf("ls \"");
110 + pool_print_seq(depth, path, '/', stdout);
111 + printf("\"\n");
112 + fflush(stdout);
113 +}
114 +
115 static const char *get_response_line(void)
116 {
117 const char *line = buffer_read_line(&report_buffer);
@@ -97,14 +122,69 @@ static const char *get_response_line(void)
122 die("unexpected end of fast-import feedback");
123 }
124
100 -void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
125 +void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input)
126 {
127 if (mode == REPO_MODE_LNK) {
128 /* svn symlink blobs start with "link " */
129 buffer_skip_bytes(input, 5);
130 len -= 5;
131 }
107 - printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
132 + printf("data %"PRIu32"\n", len);
133 buffer_copy_bytes(input, len);
134 fputc('\n', stdout);
135 }
136 +
137 +static int parse_ls_response(const char *response, uint32_t *mode,
138 + struct strbuf *dataref)
139 +{
140 + const char *tab;
141 + const char *response_end;
142 +
143 + assert(response);
144 + response_end = response + strlen(response);
145 +
146 + if (*response == 'm') { /* Missing. */
147 + errno = ENOENT;
148 + return -1;
149 + }
150 +
151 + /* Mode. */
152 + if (response_end - response < strlen("100644") ||
153 + response[strlen("100644")] != ' ')
154 + die("invalid ls response: missing mode: %s", response);
155 + *mode = 0;
156 + for (; *response != ' '; response++) {
157 + char ch = *response;
158 + if (ch < '0' || ch > '7')
159 + die("invalid ls response: mode is not octal: %s", response);
160 + *mode *= 8;
161 + *mode += ch - '0';
162 + }
163 +
164 + /* ' blob ' or ' tree ' */
165 + if (response_end - response < strlen(" blob ") ||
166 + (response[1] != 'b' && response[1] != 't'))
167 + die("unexpected ls response: not a tree or blob: %s", response);
168 + response += strlen(" blob ");
169 +
170 + /* Dataref. */
171 + tab = memchr(response, '\t', response_end - response);
172 + if (!tab)
173 + die("invalid ls response: missing tab: %s", response);
174 + strbuf_add(dataref, response, tab - response);
175 + return 0;
176 +}
177 +
178 +int fast_export_ls_rev(uint32_t rev, uint32_t depth, const uint32_t *path,
179 + uint32_t *mode, struct strbuf *dataref)
180 +{
181 + ls_from_rev(rev, depth, path);
182 + return parse_ls_response(get_response_line(), mode, dataref);
183 +}
184 +
185 +int fast_export_ls(uint32_t depth, const uint32_t *path,
186 + uint32_t *mode, struct strbuf *dataref)
187 +{
188 + ls_from_active_commit(depth, path);
189 + return parse_ls_response(get_response_line(), mode, dataref);
190 +}
vcs-svn/fast_export.h
+14 -8
@@ -1,19 +1,25 @@
1 #ifndef FAST_EXPORT_H_
2 #define FAST_EXPORT_H_
3
4 -#include "line_buffer.h"
4 +struct strbuf;
5 +struct line_buffer;
6
7 void fast_export_init(int fd);
8 void fast_export_deinit(void);
9 void fast_export_reset(void);
10
10 -void fast_export_delete(uint32_t depth, uint32_t *path);
11 -void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
12 - uint32_t mark);
13 -void fast_export_begin_commit(uint32_t revision);
14 -void fast_export_commit(uint32_t revision, uint32_t author, char *log,
11 +void fast_export_delete(uint32_t depth, const uint32_t *path);
12 +void fast_export_modify(uint32_t depth, const uint32_t *path,
13 + uint32_t mode, const char *dataref);
14 +void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,
15 uint32_t uuid, uint32_t url, unsigned long timestamp);
16 -void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
17 - struct line_buffer *input);
16 +void fast_export_end_commit(uint32_t revision);
17 +void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);
18 +
19 +/* If there is no such file at that rev, returns -1, errno == ENOENT. */
20 +int fast_export_ls_rev(uint32_t rev, uint32_t depth, const uint32_t *path,
21 + uint32_t *mode_out, struct strbuf *dataref_out);
22 +int fast_export_ls(uint32_t depth, const uint32_t *path,
23 + uint32_t *mode_out, struct strbuf *dataref_out);
24
25 #endif
vcs-svn/repo_tree.c
+37 -298
@@ -4,322 +4,61 @@
4 */
5
6 #include "git-compat-util.h"
7 -
8 -#include "string_pool.h"
7 +#include "strbuf.h"
8 #include "repo_tree.h"
10 -#include "obj_pool.h"
9 #include "fast_export.h"
10
13 -#include "trp.h"
14 -
15 -struct repo_dirent {
16 - uint32_t name_offset;
17 - struct trp_node children;
18 - uint32_t mode;
19 - uint32_t content_offset;
20 -};
21 -
22 -struct repo_dir {
23 - struct trp_root entries;
24 -};
25 -
26 -struct repo_commit {
27 - uint32_t root_dir_offset;
28 -};
29 -
30 -/* Memory pools for commit, dir and dirent */
31 -obj_pool_gen(commit, struct repo_commit, 4096)
32 -obj_pool_gen(dir, struct repo_dir, 4096)
33 -obj_pool_gen(dent, struct repo_dirent, 4096)
34 -
35 -static uint32_t active_commit;
36 -static uint32_t mark;
37 -
38 -static int repo_dirent_name_cmp(const void *a, const void *b);
39 -
40 -/* Treap for directory entries */
41 -trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp);
42 -
43 -uint32_t next_blob_mark(void)
11 +const char *repo_read_path(const uint32_t *path)
12 {
45 - return mark++;
46 -}
13 + int err;
14 + uint32_t dummy;
15 + static struct strbuf buf = STRBUF_INIT;
16
48 -static struct repo_dir *repo_commit_root_dir(struct repo_commit *commit)
49 -{
50 - return dir_pointer(commit->root_dir_offset);
51 -}
52 -
53 -static struct repo_dirent *repo_first_dirent(struct repo_dir *dir)
54 -{
55 - return dent_first(&dir->entries);
56 -}
57 -
58 -static int repo_dirent_name_cmp(const void *a, const void *b)
59 -{
60 - const struct repo_dirent *dent1 = a, *dent2 = b;
61 - uint32_t a_offset = dent1->name_offset;
62 - uint32_t b_offset = dent2->name_offset;
63 - return (a_offset > b_offset) - (a_offset < b_offset);
64 -}
65 -
66 -static int repo_dirent_is_dir(struct repo_dirent *dent)
67 -{
68 - return dent != NULL && dent->mode == REPO_MODE_DIR;
69 -}
70 -
71 -static struct repo_dir *repo_dir_from_dirent(struct repo_dirent *dent)
72 -{
73 - if (!repo_dirent_is_dir(dent))
17 + strbuf_reset(&buf);
18 + err = fast_export_ls(REPO_MAX_PATH_DEPTH, path, &dummy, &buf);
19 + if (err) {
20 + if (errno != ENOENT)
21 + die_errno("BUG: unexpected fast_export_ls error");
22 return NULL;
75 - return dir_pointer(dent->content_offset);
76 -}
77 -
78 -static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir)
79 -{
80 - uint32_t orig_o, new_o;
81 - orig_o = dir_offset(orig_dir);
82 - if (orig_o >= dir_pool.committed)
83 - return orig_dir;
84 - new_o = dir_alloc(1);
85 - orig_dir = dir_pointer(orig_o);
86 - *dir_pointer(new_o) = *orig_dir;
87 - return dir_pointer(new_o);
88 -}
89 -
90 -static struct repo_dirent *repo_read_dirent(uint32_t revision,
91 - const uint32_t *path)
92 -{
93 - uint32_t name = 0;
94 - struct repo_dirent *key = dent_pointer(dent_alloc(1));
95 - struct repo_dir *dir = NULL;
96 - struct repo_dirent *dent = NULL;
97 - dir = repo_commit_root_dir(commit_pointer(revision));
98 - while (~(name = *path++)) {
99 - key->name_offset = name;
100 - dent = dent_search(&dir->entries, key);
101 - if (dent == NULL || !repo_dirent_is_dir(dent))
102 - break;
103 - dir = repo_dir_from_dirent(dent);
104 - }
105 - dent_free(1);
106 - return dent;
107 -}
108 -
109 -static void repo_write_dirent(const uint32_t *path, uint32_t mode,
110 - uint32_t content_offset, uint32_t del)
111 -{
112 - uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0;
113 - struct repo_dir *dir;
114 - struct repo_dirent *key;
115 - struct repo_dirent *dent = NULL;
116 - revision = active_commit;
117 - dir = repo_commit_root_dir(commit_pointer(revision));
118 - dir = repo_clone_dir(dir);
119 - commit_pointer(revision)->root_dir_offset = dir_offset(dir);
120 - while (~(name = *path++)) {
121 - parent_dir_o = dir_offset(dir);
122 -
123 - key = dent_pointer(dent_alloc(1));
124 - key->name_offset = name;
125 -
126 - dent = dent_search(&dir->entries, key);
127 - if (dent == NULL)
128 - dent = key;
129 - else
130 - dent_free(1);
131 -
132 - if (dent == key) {
133 - dent->mode = REPO_MODE_DIR;
134 - dent->content_offset = 0;
135 - dent = dent_insert(&dir->entries, dent);
136 - }
137 -
138 - if (dent_offset(dent) < dent_pool.committed) {
139 - dir_o = repo_dirent_is_dir(dent) ?
140 - dent->content_offset : ~0;
141 - dent_remove(&dir->entries, dent);
142 - dent = dent_pointer(dent_alloc(1));
143 - dent->name_offset = name;
144 - dent->mode = REPO_MODE_DIR;
145 - dent->content_offset = dir_o;
146 - dent = dent_insert(&dir->entries, dent);
147 - }
148 -
149 - dir = repo_dir_from_dirent(dent);
150 - dir = repo_clone_dir(dir);
151 - dent->content_offset = dir_offset(dir);
23 }
153 - if (dent == NULL)
154 - return;
155 - dent->mode = mode;
156 - dent->content_offset = content_offset;
157 - if (del && ~parent_dir_o)
158 - dent_remove(&dir_pointer(parent_dir_o)->entries, dent);
159 -}
160 -
161 -uint32_t repo_read_path(const uint32_t *path)
162 -{
163 - uint32_t content_offset = 0;
164 - struct repo_dirent *dent = repo_read_dirent(active_commit, path);
165 - if (dent != NULL)
166 - content_offset = dent->content_offset;
167 - return content_offset;
24 + return buf.buf;
25 }
26
27 uint32_t repo_read_mode(const uint32_t *path)
28 {
172 - struct repo_dirent *dent = repo_read_dirent(active_commit, path);
173 - if (dent == NULL)
174 - die("invalid dump: path to be modified is missing");
175 - return dent->mode;
29 + int err;
30 + uint32_t result;
31 + static struct strbuf dummy = STRBUF_INIT;
32 +
33 + strbuf_reset(&dummy);
34 + err = fast_export_ls(REPO_MAX_PATH_DEPTH, path, &result, &dummy);
35 + if (err) {
36 + if (errno != ENOENT)
37 + die_errno("BUG: unexpected fast_export_ls error");
38 + /* Treat missing paths as directories. */
39 + return REPO_MODE_DIR;
40 + }
41 + return result;
42 }
43
44 void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)
45 {
180 - uint32_t mode = 0, content_offset = 0;
181 - struct repo_dirent *src_dent;
182 - src_dent = repo_read_dirent(revision, src);
183 - if (src_dent != NULL) {
184 - mode = src_dent->mode;
185 - content_offset = src_dent->content_offset;
186 - repo_write_dirent(dst, mode, content_offset, 0);
46 + int err;
47 + uint32_t mode;
48 + static struct strbuf data = STRBUF_INIT;
49 +
50 + strbuf_reset(&data);
51 + err = fast_export_ls_rev(revision, REPO_MAX_PATH_DEPTH, src, &mode, &data);
52 + if (err) {
53 + if (errno != ENOENT)
54 + die_errno("BUG: unexpected fast_export_ls_rev error");
55 + fast_export_delete(REPO_MAX_PATH_DEPTH, dst);
56 + return;
57 }
188 -}
189 -
190 -void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
191 -{
192 - repo_write_dirent(path, mode, blob_mark, 0);
58 + fast_export_modify(REPO_MAX_PATH_DEPTH, dst, mode, data.buf);
59 }
60
61 void repo_delete(uint32_t *path)
62 {
197 - repo_write_dirent(path, 0, 0, 1);
198 -}
199 -
200 -static void repo_git_add_r(uint32_t depth, uint32_t *path, struct repo_dir *dir);
201 -
202 -static void repo_git_add(uint32_t depth, uint32_t *path, struct repo_dirent *dent)
203 -{
204 - if (repo_dirent_is_dir(dent))
205 - repo_git_add_r(depth, path, repo_dir_from_dirent(dent));
206 - else
207 - fast_export_modify(depth, path,
208 - dent->mode, dent->content_offset);
209 -}
210 -
211 -static void repo_git_add_r(uint32_t depth, uint32_t *path, struct repo_dir *dir)
212 -{
213 - struct repo_dirent *de = repo_first_dirent(dir);
214 - while (de) {
215 - path[depth] = de->name_offset;
216 - repo_git_add(depth + 1, path, de);
217 - de = dent_next(&dir->entries, de);
218 - }
219 -}
220 -
221 -static void repo_diff_r(uint32_t depth, uint32_t *path, struct repo_dir *dir1,
222 - struct repo_dir *dir2)
223 -{
224 - struct repo_dirent *de1, *de2;
225 - de1 = repo_first_dirent(dir1);
226 - de2 = repo_first_dirent(dir2);
227 -
228 - while (de1 && de2) {
229 - if (de1->name_offset < de2->name_offset) {
230 - path[depth] = de1->name_offset;
231 - fast_export_delete(depth + 1, path);
232 - de1 = dent_next(&dir1->entries, de1);
233 - continue;
234 - }
235 - if (de1->name_offset > de2->name_offset) {
236 - path[depth] = de2->name_offset;
237 - repo_git_add(depth + 1, path, de2);
238 - de2 = dent_next(&dir2->entries, de2);
239 - continue;
240 - }
241 - path[depth] = de1->name_offset;
242 -
243 - if (de1->mode == de2->mode &&
244 - de1->content_offset == de2->content_offset) {
245 - ; /* No change. */
246 - } else if (repo_dirent_is_dir(de1) && repo_dirent_is_dir(de2)) {
247 - repo_diff_r(depth + 1, path,
248 - repo_dir_from_dirent(de1),
249 - repo_dir_from_dirent(de2));
250 - } else if (!repo_dirent_is_dir(de1) && !repo_dirent_is_dir(de2)) {
251 - repo_git_add(depth + 1, path, de2);
252 - } else {
253 - fast_export_delete(depth + 1, path);
254 - repo_git_add(depth + 1, path, de2);
255 - }
256 - de1 = dent_next(&dir1->entries, de1);
257 - de2 = dent_next(&dir2->entries, de2);
258 - }
259 - while (de1) {
260 - path[depth] = de1->name_offset;
261 - fast_export_delete(depth + 1, path);
262 - de1 = dent_next(&dir1->entries, de1);
263 - }
264 - while (de2) {
265 - path[depth] = de2->name_offset;
266 - repo_git_add(depth + 1, path, de2);
267 - de2 = dent_next(&dir2->entries, de2);
268 - }
269 -}
270 -
271 -static uint32_t path_stack[REPO_MAX_PATH_DEPTH];
272 -
273 -void repo_diff(uint32_t r1, uint32_t r2)
274 -{
275 - repo_diff_r(0,
276 - path_stack,
277 - repo_commit_root_dir(commit_pointer(r1)),
278 - repo_commit_root_dir(commit_pointer(r2)));
279 -}
280 -
281 -void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
282 - uint32_t url, unsigned long timestamp)
283 -{
284 - fast_export_commit(revision, author, log, uuid, url, timestamp);
285 - dent_commit();
286 - dir_commit();
287 - active_commit = commit_alloc(1);
288 - commit_pointer(active_commit)->root_dir_offset =
289 - commit_pointer(active_commit - 1)->root_dir_offset;
290 -}
291 -
292 -static void mark_init(void)
293 -{
294 - uint32_t i;
295 - mark = 1024 * 1024 * 1024;
296 - for (i = 0; i < dent_pool.size; i++)
297 - if (!repo_dirent_is_dir(dent_pointer(i)) &&
298 - dent_pointer(i)->content_offset > mark)
299 - mark = dent_pointer(i)->content_offset;
300 - mark++;
301 -}
302 -
303 -void repo_init(void)
304 -{
305 - mark_init();
306 - if (commit_pool.size == 0) {
307 - /* Create empty tree for commit 0. */
308 - commit_alloc(1);
309 - commit_pointer(0)->root_dir_offset = dir_alloc(1);
310 - dir_pointer(0)->entries.trp_root = ~0;
311 - dir_commit();
312 - }
313 - /* Preallocate next commit, ready for changes. */
314 - active_commit = commit_alloc(1);
315 - commit_pointer(active_commit)->root_dir_offset =
316 - commit_pointer(active_commit - 1)->root_dir_offset;
317 -}
318 -
319 -void repo_reset(void)
320 -{
321 - pool_reset();
322 - commit_reset();
323 - dir_reset();
324 - dent_reset();
63 + fast_export_delete(REPO_MAX_PATH_DEPTH, path);
64 }
vcs-svn/repo_tree.h
+1 -1
@@ -14,7 +14,7 @@
14 uint32_t next_blob_mark(void);
15 void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);
16 void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);
17 -uint32_t repo_read_path(const uint32_t *path);
17 +const char *repo_read_path(const uint32_t *path);
18 uint32_t repo_read_mode(const uint32_t *path);
19 void repo_delete(uint32_t *path);
20 void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
vcs-svn/string_pool.c
+1 -1
@@ -65,7 +65,7 @@ uint32_t pool_tok_r(char *str, const char *delim, char **saveptr)
65 return token ? pool_intern(token) : ~0;
66 }
67
68 -void pool_print_seq(uint32_t len, uint32_t *seq, char delim, FILE *stream)
68 +void pool_print_seq(uint32_t len, const uint32_t *seq, char delim, FILE *stream)
69 {
70 uint32_t i;
71 for (i = 0; i < len && ~seq[i]; i++) {
vcs-svn/string_pool.h
+1 -1
@@ -4,7 +4,7 @@
4 uint32_t pool_intern(const char *key);
5 const char *pool_fetch(uint32_t entry);
6 uint32_t pool_tok_r(char *str, const char *delim, char **saveptr);
7 -void pool_print_seq(uint32_t len, uint32_t *seq, char delim, FILE *stream);
7 +void pool_print_seq(uint32_t len, const uint32_t *seq, char delim, FILE *stream);
8 uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str);
9 void pool_reset(void);
10
vcs-svn/svndump.c
+36 -17
@@ -36,6 +36,8 @@ obj_pool_gen(log, char, 4096)
36
37 static struct line_buffer input = LINE_BUFFER_INIT;
38
39 +#define REPORT_FILENO 3
40 +
41 static char *log_copy(uint32_t length, const char *log)
42 {
43 char *buffer;
@@ -202,15 +204,21 @@ static void read_props(void)
204
205 static void handle_node(void)
206 {
205 - uint32_t mark = 0;
207 const uint32_t type = node_ctx.type;
208 const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
209 const int have_text = node_ctx.textLength != LENGTH_UNKNOWN;
210 + /*
211 + * Old text for this node:
212 + * NULL - directory or bug
213 + * empty_blob - empty
214 + * "<dataref>" - data retrievable from fast-import
215 + */
216 + static const char *const empty_blob = "::empty::";
217 + const char *old_data = NULL;
218
219 if (node_ctx.text_delta)
220 die("text deltas not supported");
212 - if (have_text)
213 - mark = next_blob_mark();
221 +
222 if (node_ctx.action == NODEACT_DELETE) {
223 if (have_text || have_props || node_ctx.srcRev)
224 die("invalid dump: deletion node has "
@@ -230,15 +238,15 @@ static void handle_node(void)
238 die("invalid dump: directories cannot have text attached");
239
240 /*
233 - * Decide on the new content (mark) and mode (node_ctx.type).
241 + * Find old content (old_data) and decide on the new mode.
242 */
243 if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {
244 if (type != REPO_MODE_DIR)
245 die("invalid dump: root of tree is not a regular file");
246 + old_data = NULL;
247 } else if (node_ctx.action == NODEACT_CHANGE) {
248 uint32_t mode;
240 - if (!have_text)
241 - mark = repo_read_path(node_ctx.dst);
249 + old_data = repo_read_path(node_ctx.dst);
250 mode = repo_read_mode(node_ctx.dst);
251 if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
252 die("invalid dump: cannot modify a directory into a file");
@@ -246,7 +254,11 @@ static void handle_node(void)
254 die("invalid dump: cannot modify a file into a directory");
255 node_ctx.type = mode;
256 } else if (node_ctx.action == NODEACT_ADD) {
249 - if (!have_text && type != REPO_MODE_DIR)
257 + if (type == REPO_MODE_DIR)
258 + old_data = NULL;
259 + else if (have_text)
260 + old_data = empty_blob;
261 + else
262 die("invalid dump: adds node without text");
263 } else {
264 die("invalid dump: Node-path block lacks Node-action");
@@ -265,24 +277,34 @@ static void handle_node(void)
277 /*
278 * Save the result.
279 */
268 - repo_add(node_ctx.dst, node_ctx.type, mark);
269 - if (have_text)
270 - fast_export_blob(node_ctx.type, mark,
271 - node_ctx.textLength, &input);
280 + if (type == REPO_MODE_DIR) /* directories are not tracked. */
281 + return;
282 + assert(old_data);
283 + if (old_data == empty_blob)
284 + /* For the fast_export_* functions, NULL means empty. */
285 + old_data = NULL;
286 + if (!have_text) {
287 + fast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst,
288 + node_ctx.type, old_data);
289 + return;
290 + }
291 + fast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst,
292 + node_ctx.type, "inline");
293 + fast_export_data(node_ctx.type, node_ctx.textLength, &input);
294 }
295
296 static void begin_revision(void)
297 {
298 if (!rev_ctx.revision) /* revision 0 gets no git commit. */
299 return;
278 - fast_export_begin_commit(rev_ctx.revision);
300 + fast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
301 + dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
302 }
303
304 static void end_revision(void)
305 {
306 if (rev_ctx.revision)
284 - repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
285 - dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
307 + fast_export_end_commit(rev_ctx.revision);
308 }
309
310 void svndump_read(const char *url)
@@ -383,7 +405,6 @@ int svndump_init(const char *filename)
405 {
406 if (buffer_init(&input, filename))
407 return error("cannot open %s: %s", filename, strerror(errno));
386 - repo_init();
408 fast_export_init(REPORT_FILENO);
409 reset_dump_ctx(~0);
410 reset_rev_ctx(0);
@@ -396,7 +417,6 @@ void svndump_deinit(void)
417 {
418 log_reset();
419 fast_export_deinit();
399 - repo_reset();
420 reset_dump_ctx(~0);
421 reset_rev_ctx(0);
422 reset_node_ctx(NULL);
@@ -411,7 +431,6 @@ void svndump_reset(void)
431 log_reset();
432 fast_export_reset();
433 buffer_reset(&input);
414 - repo_reset();
434 reset_dump_ctx(~0);
435 reset_rev_ctx(0);
436 reset_node_ctx(NULL);