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);