~svn/ubuntu/raring/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_svn/editor.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * editor.c :  Driving and consuming an editor across an svn connection
 
3
 *
 
4
 * ====================================================================
 
5
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
6
 *
 
7
 * This software is licensed as described in the file COPYING, which
 
8
 * you should have received as part of this distribution.  The terms
 
9
 * are also available at http://subversion.tigris.org/license-1.html.
 
10
 * If newer versions of this license are posted there, you may use a
 
11
 * newer version instead, at your option.
 
12
 *
 
13
 * This software consists of voluntary contributions made by many
 
14
 * individuals.  For exact contribution history, see the revision
 
15
 * history and logs, available at http://subversion.tigris.org/.
 
16
 * ====================================================================
 
17
 */
 
18
 
 
19
 
 
20
 
 
21
#define APR_WANT_STRFUNC
 
22
#include <apr_want.h>
 
23
#include <apr_general.h>
 
24
#include <apr_strings.h>
 
25
#include <apr_md5.h>
 
26
 
 
27
#include <assert.h>
 
28
 
 
29
#include "svn_types.h"
 
30
#include "svn_string.h"
 
31
#include "svn_error.h"
 
32
#include "svn_path.h"
 
33
#include "svn_delta.h"
 
34
#include "svn_ra_svn.h"
 
35
#include "svn_pools.h"
 
36
#include "svn_private_config.h"
 
37
 
 
38
#include "ra_svn.h"
 
39
 
 
40
/*
 
41
 * Both the client and server in the svn protocol need to drive and
 
42
 * consume editors.  For a commit, the client drives and the server
 
43
 * consumes; for an update/switch/status/diff, the server drives and
 
44
 * the client consumes.  This file provides a generic framework for
 
45
 * marshalling and unmarshalling editor operations over an svn
 
46
 * connection; both ends are useful for both server and client.
 
47
 */
 
48
 
 
49
typedef struct {
 
50
  svn_ra_svn_conn_t *conn;
 
51
  svn_ra_svn_edit_callback callback;    /* Called on successful completion. */
 
52
  void *callback_baton;
 
53
  int next_token;
 
54
} ra_svn_edit_baton_t;
 
55
 
 
56
/* Works for both directories and files. */
 
57
typedef struct {
 
58
  svn_ra_svn_conn_t *conn;
 
59
  apr_pool_t *pool;
 
60
  ra_svn_edit_baton_t *eb;
 
61
  const char *token;
 
62
} ra_svn_baton_t;
 
63
 
 
64
typedef struct {
 
65
  const svn_delta_editor_t *editor;
 
66
  void *edit_baton;
 
67
  apr_hash_t *tokens;
 
68
  svn_boolean_t *aborted;
 
69
  apr_pool_t *pool;
 
70
} ra_svn_driver_state_t;
 
71
 
 
72
typedef struct {
 
73
  const char *token;
 
74
  void *baton;
 
75
  svn_error_t *err;                     /* Tracks delayed errors. */
 
76
  apr_pool_t *pool;
 
77
} ra_svn_token_entry_t;
 
78
 
 
79
/* --- CONSUMING AN EDITOR BY PASSING EDIT OPERATIONS OVER THE NET --- */
 
80
 
 
81
static const char *make_token(char type, ra_svn_edit_baton_t *eb,
 
82
                              apr_pool_t *pool)
 
83
{
 
84
  return apr_psprintf(pool, "%c%d", type, eb->next_token++);
 
85
}
 
86
 
 
87
static ra_svn_baton_t *ra_svn_make_baton(svn_ra_svn_conn_t *conn,
 
88
                                         apr_pool_t *pool,
 
89
                                         ra_svn_edit_baton_t *eb,
 
90
                                         const char *token)
 
91
{
 
92
  ra_svn_baton_t *b;
 
93
 
 
94
  b = apr_palloc(pool, sizeof(*b));
 
95
  b->conn = conn;
 
96
  b->pool = pool;
 
97
  b->eb = eb;
 
98
  b->token = token;
 
99
  return b;
 
100
}
 
101
 
 
102
static svn_error_t *ra_svn_target_rev(void *edit_baton, svn_revnum_t rev,
 
103
                                      apr_pool_t *pool)
 
104
{
 
105
  ra_svn_edit_baton_t *eb = edit_baton;
 
106
 
 
107
  SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "target-rev", "r", rev));
 
108
  SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
 
109
  return SVN_NO_ERROR;
 
110
}
 
111
 
 
112
static svn_error_t *ra_svn_open_root(void *edit_baton, svn_revnum_t rev,
 
113
                                     apr_pool_t *pool, void **root_baton)
 
114
{
 
115
  ra_svn_edit_baton_t *eb = edit_baton;
 
116
  const char *token = make_token('d', eb, pool);
 
117
 
 
118
  SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "open-root", "(?r)c", rev,
 
119
                               token));
 
120
  SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
 
121
  *root_baton = ra_svn_make_baton(eb->conn, pool, eb, token);
 
122
  return SVN_NO_ERROR;
 
123
}
 
124
 
 
125
static svn_error_t *ra_svn_delete_entry(const char *path, svn_revnum_t rev,
 
126
                                        void *parent_baton, apr_pool_t *pool)
 
127
{
 
128
  ra_svn_baton_t *b = parent_baton;
 
129
 
 
130
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "delete-entry", "c(?r)c",
 
131
                               path, rev, b->token));
 
132
  SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
 
133
  return SVN_NO_ERROR;
 
134
}
 
135
 
 
136
static svn_error_t *ra_svn_add_dir(const char *path, void *parent_baton,
 
137
                                   const char *copy_path,
 
138
                                   svn_revnum_t copy_rev,
 
139
                                   apr_pool_t *pool, void **child_baton)
 
140
{
 
141
  ra_svn_baton_t *b = parent_baton;
 
142
  const char *token = make_token('d', b->eb, pool);
 
143
 
 
144
  assert((copy_path && SVN_IS_VALID_REVNUM(copy_rev))
 
145
         || (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev)));
 
146
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "add-dir", "ccc(?cr)", path,
 
147
                               b->token, token, copy_path, copy_rev));
 
148
  SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
 
149
  *child_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
 
150
  return SVN_NO_ERROR;
 
151
}
 
152
 
 
153
static svn_error_t *ra_svn_open_dir(const char *path, void *parent_baton,
 
154
                                    svn_revnum_t rev, apr_pool_t *pool,
 
155
                                    void **child_baton)
 
156
{
 
157
  ra_svn_baton_t *b = parent_baton;
 
158
  const char *token = make_token('d', b->eb, pool);
 
159
 
 
160
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "open-dir", "ccc(?r)",
 
161
                               path, b->token, token, rev));
 
162
  SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
 
163
  *child_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
 
164
  return SVN_NO_ERROR;
 
165
}
 
166
 
 
167
static svn_error_t *ra_svn_change_dir_prop(void *dir_baton, const char *name,
 
168
                                           const svn_string_t *value,
 
169
                                           apr_pool_t *pool)
 
170
{
 
171
  ra_svn_baton_t *b = dir_baton;
 
172
 
 
173
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "change-dir-prop", "cc(?s)",
 
174
                               b->token, name, value));
 
175
  return SVN_NO_ERROR;
 
176
}
 
177
 
 
178
static svn_error_t *ra_svn_close_dir(void *dir_baton, apr_pool_t *pool)
 
179
{
 
180
  ra_svn_baton_t *b = dir_baton;
 
181
 
 
182
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "close-dir", "c", b->token));
 
183
  SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
 
184
  return SVN_NO_ERROR;
 
185
}
 
186
 
 
187
static svn_error_t *ra_svn_add_file(const char *path,
 
188
                                    void *parent_baton,
 
189
                                    const char *copy_path,
 
190
                                    svn_revnum_t copy_rev,
 
191
                                    apr_pool_t *pool,
 
192
                                    void **file_baton)
 
193
{
 
194
  ra_svn_baton_t *b = parent_baton;
 
195
  const char *token = make_token('c', b->eb, pool);
 
196
 
 
197
  assert((copy_path && SVN_IS_VALID_REVNUM(copy_rev))
 
198
         || (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev)));
 
199
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "add-file", "ccc(?cr)", path,
 
200
                               b->token, token, copy_path, copy_rev));
 
201
  *file_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
 
202
  return SVN_NO_ERROR;
 
203
}
 
204
 
 
205
static svn_error_t *ra_svn_open_file(const char *path,
 
206
                                     void *parent_baton,
 
207
                                     svn_revnum_t rev,
 
208
                                     apr_pool_t *pool,
 
209
                                     void **file_baton)
 
210
{
 
211
  ra_svn_baton_t *b = parent_baton;
 
212
  const char *token = make_token('c', b->eb, pool);
 
213
 
 
214
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "open-file", "ccc(?r)",
 
215
                               path, b->token, token, rev));
 
216
  *file_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
 
217
  return SVN_NO_ERROR;
 
218
}
 
219
 
 
220
static svn_error_t *ra_svn_svndiff_handler(void *baton, const char *data,
 
221
                                           apr_size_t *len)
 
222
{
 
223
  ra_svn_baton_t *b = baton;
 
224
  svn_string_t str;
 
225
 
 
226
  str.data = data;
 
227
  str.len = *len;
 
228
  return svn_ra_svn_write_string(b->conn, b->pool, &str);
 
229
}
 
230
 
 
231
static svn_error_t *ra_svn_svndiff_close_handler(void *baton)
 
232
{
 
233
  ra_svn_baton_t *b = baton;
 
234
 
 
235
  SVN_ERR(svn_ra_svn_write_cstring(b->conn, b->pool, ""));
 
236
  return SVN_NO_ERROR;
 
237
}
 
238
 
 
239
static svn_error_t *ra_svn_apply_textdelta(void *file_baton,
 
240
                                           const char *base_checksum,
 
241
                                           apr_pool_t *pool,
 
242
                                           svn_txdelta_window_handler_t *wh,
 
243
                                           void **wh_baton)
 
244
{
 
245
  ra_svn_baton_t *b = file_baton;
 
246
  svn_stream_t *diff_stream;
 
247
 
 
248
  /* Tell the other side we're starting a text delta. */
 
249
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "c(?c)",
 
250
                               b->token, base_checksum));
 
251
 
 
252
  /* Transform the window stream to an svndiff stream.  Reuse the
 
253
   * file baton for the stream handler, since it has all the
 
254
   * needed information. */
 
255
  diff_stream = svn_stream_create(b, pool);
 
256
  svn_stream_set_write(diff_stream, ra_svn_svndiff_handler);
 
257
  svn_stream_set_close(diff_stream, ra_svn_svndiff_close_handler);
 
258
  svn_txdelta_to_svndiff(diff_stream, pool, wh, wh_baton);
 
259
  return SVN_NO_ERROR;
 
260
}
 
261
  
 
262
static svn_error_t *ra_svn_change_file_prop(void *file_baton,
 
263
                                            const char *name,
 
264
                                            const svn_string_t *value,
 
265
                                            apr_pool_t *pool)
 
266
{
 
267
  ra_svn_baton_t *b = file_baton;
 
268
 
 
269
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "change-file-prop", "cc(?s)",
 
270
                               b->token, name, value));
 
271
  return SVN_NO_ERROR;
 
272
}
 
273
 
 
274
static svn_error_t *ra_svn_close_file(void *file_baton,
 
275
                                      const char *text_checksum,
 
276
                                      apr_pool_t *pool)
 
277
{
 
278
  ra_svn_baton_t *b = file_baton;
 
279
 
 
280
  SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "close-file", "c(?c)",
 
281
                               b->token, text_checksum));
 
282
  SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
 
283
  return SVN_NO_ERROR;
 
284
}
 
285
 
 
286
static svn_error_t *ra_svn_close_edit(void *edit_baton, apr_pool_t *pool)
 
287
{
 
288
  ra_svn_edit_baton_t *eb = edit_baton;
 
289
 
 
290
  SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "close-edit", ""));
 
291
  SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
 
292
  if (eb->callback)
 
293
    SVN_ERR(eb->callback(eb->callback_baton));
 
294
  return SVN_NO_ERROR;
 
295
}
 
296
 
 
297
static svn_error_t *ra_svn_abort_edit(void *edit_baton, apr_pool_t *pool)
 
298
{
 
299
  ra_svn_edit_baton_t *eb = edit_baton;
 
300
 
 
301
  SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "abort-edit", ""));
 
302
  SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
 
303
  return SVN_NO_ERROR;
 
304
}
 
305
 
 
306
void svn_ra_svn_get_editor(const svn_delta_editor_t **editor,
 
307
                           void **edit_baton, svn_ra_svn_conn_t *conn,
 
308
                           apr_pool_t *pool, svn_ra_svn_edit_callback callback,
 
309
                           void *callback_baton)
 
310
{
 
311
  svn_delta_editor_t *ra_svn_editor;
 
312
  ra_svn_edit_baton_t *eb;
 
313
 
 
314
  if (svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_EDIT_PIPELINE))
 
315
    {
 
316
      svn_ra_svn__get_editorp(editor, edit_baton, conn, pool, callback,
 
317
                              callback_baton);
 
318
      return;
 
319
    }
 
320
 
 
321
  eb = apr_palloc(pool, sizeof(*eb));
 
322
  eb->conn = conn;
 
323
  eb->callback = callback;
 
324
  eb->callback_baton = callback_baton;
 
325
  eb->next_token = 0;
 
326
 
 
327
  ra_svn_editor = svn_delta_default_editor(pool);
 
328
  ra_svn_editor->set_target_revision = ra_svn_target_rev;
 
329
  ra_svn_editor->open_root = ra_svn_open_root;
 
330
  ra_svn_editor->delete_entry = ra_svn_delete_entry;
 
331
  ra_svn_editor->add_directory = ra_svn_add_dir;
 
332
  ra_svn_editor->open_directory = ra_svn_open_dir;
 
333
  ra_svn_editor->change_dir_prop = ra_svn_change_dir_prop;
 
334
  ra_svn_editor->close_directory = ra_svn_close_dir;
 
335
  ra_svn_editor->add_file = ra_svn_add_file;
 
336
  ra_svn_editor->open_file = ra_svn_open_file;
 
337
  ra_svn_editor->apply_textdelta = ra_svn_apply_textdelta;
 
338
  ra_svn_editor->change_file_prop = ra_svn_change_file_prop;
 
339
  ra_svn_editor->close_file = ra_svn_close_file;
 
340
  ra_svn_editor->close_edit = ra_svn_close_edit;
 
341
  ra_svn_editor->abort_edit = ra_svn_abort_edit;
 
342
 
 
343
  *editor = ra_svn_editor;
 
344
  *edit_baton = eb;
 
345
}
 
346
 
 
347
/* --- DRIVING AN EDITOR --- */
 
348
 
 
349
static apr_status_t clear_token_err(void *arg)
 
350
{
 
351
  ra_svn_token_entry_t *entry = arg;
 
352
 
 
353
  svn_error_clear(entry->err);
 
354
  return APR_SUCCESS;
 
355
}
 
356
 
 
357
/* Store a token entry.  The token string will be copied into pool. */
 
358
static ra_svn_token_entry_t *store_token(ra_svn_driver_state_t *ds,
 
359
                                         void *baton, const char *token,
 
360
                                         apr_pool_t *pool)
 
361
{
 
362
  ra_svn_token_entry_t *entry;
 
363
 
 
364
  entry = apr_palloc(pool, sizeof(*entry));
 
365
  entry->token = apr_pstrdup(pool, token);
 
366
  entry->baton = baton;
 
367
  entry->err = NULL;
 
368
  entry->pool = pool;
 
369
  apr_hash_set(ds->tokens, entry->token, APR_HASH_KEY_STRING, entry);
 
370
  apr_pool_cleanup_register(pool, entry, clear_token_err,
 
371
                            apr_pool_cleanup_null);
 
372
  return entry;
 
373
}
 
374
 
 
375
static svn_error_t *lookup_token(ra_svn_driver_state_t *ds, const char *token,
 
376
                                 ra_svn_token_entry_t **entry,
 
377
                                 apr_pool_t *pool)
 
378
 
 
379
{
 
380
  *entry = apr_hash_get(ds->tokens, token, APR_HASH_KEY_STRING);
 
381
  if (!*entry)
 
382
    return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
 
383
                            _("Invalid file or dir token during edit"));
 
384
  return SVN_NO_ERROR;
 
385
}
 
386
 
 
387
static svn_error_t *ra_svn_handle_target_rev(svn_ra_svn_conn_t *conn,
 
388
                                             apr_pool_t *pool,
 
389
                                             apr_array_header_t *params,
 
390
                                             void *baton)
 
391
{
 
392
  ra_svn_driver_state_t *ds = baton;
 
393
  svn_revnum_t rev;
 
394
 
 
395
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "r", &rev));
 
396
  SVN_CMD_ERR(ds->editor->set_target_revision(ds->edit_baton, rev, pool));
 
397
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
398
  return SVN_NO_ERROR;
 
399
}
 
400
 
 
401
static svn_error_t *ra_svn_handle_open_root(svn_ra_svn_conn_t *conn,
 
402
                                            apr_pool_t *pool,
 
403
                                            apr_array_header_t *params,
 
404
                                            void *baton)
 
405
{
 
406
  ra_svn_driver_state_t *ds = baton;
 
407
  svn_revnum_t rev;
 
408
  apr_pool_t *subpool;
 
409
  const char *token;
 
410
  void *root_baton;
 
411
 
 
412
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "(?r)c", &rev, &token));
 
413
  subpool = svn_pool_create(ds->pool);
 
414
  SVN_CMD_ERR(ds->editor->open_root(ds->edit_baton, rev, subpool,
 
415
                                    &root_baton));
 
416
  store_token(ds, root_baton, token, subpool);
 
417
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
418
  return SVN_NO_ERROR;
 
419
}
 
420
 
 
421
static svn_error_t *ra_svn_handle_delete_entry(svn_ra_svn_conn_t *conn,
 
422
                                               apr_pool_t *pool,
 
423
                                               apr_array_header_t *params,
 
424
                                               void *baton)
 
425
{
 
426
  ra_svn_driver_state_t *ds = baton;
 
427
  const char *path, *token;
 
428
  svn_revnum_t rev;
 
429
  ra_svn_token_entry_t *entry;
 
430
 
 
431
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)c", &path, &rev, &token));
 
432
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
433
  path = svn_path_canonicalize(path, pool);
 
434
  SVN_CMD_ERR(ds->editor->delete_entry(path, rev, entry->baton, entry->pool));
 
435
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
436
  return SVN_NO_ERROR;
 
437
}
 
438
 
 
439
static svn_error_t *ra_svn_handle_add_dir(svn_ra_svn_conn_t *conn,
 
440
                                          apr_pool_t *pool,
 
441
                                          apr_array_header_t *params,
 
442
                                          void *baton)
 
443
{
 
444
  ra_svn_driver_state_t *ds = baton;
 
445
  const char *path, *token, *child_token, *copy_path;
 
446
  svn_revnum_t copy_rev;
 
447
  ra_svn_token_entry_t *entry;
 
448
  apr_pool_t *subpool;
 
449
  void *child_baton;
 
450
 
 
451
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "ccc(?cr)", &path, &token,
 
452
                                 &child_token, &copy_path, &copy_rev));
 
453
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
454
  subpool = svn_pool_create(entry->pool);
 
455
  path = svn_path_canonicalize(path, pool);
 
456
  if (copy_path)
 
457
    copy_path = svn_path_canonicalize(copy_path, pool);
 
458
  SVN_CMD_ERR(ds->editor->add_directory(path, entry->baton, copy_path,
 
459
                                        copy_rev, subpool, &child_baton));
 
460
  store_token(ds, child_baton, child_token, subpool);
 
461
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
462
  return SVN_NO_ERROR;
 
463
}
 
464
 
 
465
static svn_error_t *ra_svn_handle_open_dir(svn_ra_svn_conn_t *conn,
 
466
                                           apr_pool_t *pool,
 
467
                                           apr_array_header_t *params,
 
468
                                           void *baton)
 
469
{
 
470
  ra_svn_driver_state_t *ds = baton;
 
471
  const char *path, *token, *child_token;
 
472
  svn_revnum_t rev;
 
473
  ra_svn_token_entry_t *entry;
 
474
  apr_pool_t *subpool;
 
475
  void *child_baton;
 
476
 
 
477
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "ccc(?r)", &path, &token,
 
478
                                 &child_token, &rev));
 
479
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
480
  subpool = svn_pool_create(entry->pool);
 
481
  path = svn_path_canonicalize(path, pool);
 
482
  SVN_CMD_ERR(ds->editor->open_directory(path, entry->baton, rev, subpool,
 
483
                                         &child_baton));
 
484
  store_token(ds, child_baton, child_token, subpool);
 
485
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
486
  return SVN_NO_ERROR;
 
487
}
 
488
 
 
489
static svn_error_t *ra_svn_handle_change_dir_prop(svn_ra_svn_conn_t *conn,
 
490
                                                  apr_pool_t *pool,
 
491
                                                  apr_array_header_t *params,
 
492
                                                  void *baton)
 
493
{
 
494
  ra_svn_driver_state_t *ds = baton;
 
495
  const char *token, *name;
 
496
  svn_string_t *value;
 
497
  ra_svn_token_entry_t *entry;
 
498
 
 
499
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "cc(?s)", &token, &name,
 
500
                                 &value));
 
501
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
502
  if (!entry->err)
 
503
    entry->err = ds->editor->change_dir_prop(entry->baton, name, value,
 
504
                                             entry->pool);
 
505
  return SVN_NO_ERROR;
 
506
}
 
507
 
 
508
static svn_error_t *ra_svn_handle_close_dir(svn_ra_svn_conn_t *conn,
 
509
                                            apr_pool_t *pool,
 
510
                                            apr_array_header_t *params,
 
511
                                            void *baton)
 
512
{
 
513
  ra_svn_driver_state_t *ds = baton;
 
514
  const char *token;
 
515
  ra_svn_token_entry_t *entry;
 
516
 
 
517
  /* Parse and look up the directory token. */
 
518
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c", &token));
 
519
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
520
 
 
521
  /* Return any delayed errors. */
 
522
  apr_pool_cleanup_kill(entry->pool, entry, clear_token_err);
 
523
  SVN_CMD_ERR(entry->err);
 
524
 
 
525
  /* Close the directory and destroy the baton. */
 
526
  SVN_CMD_ERR(ds->editor->close_directory(entry->baton, pool));
 
527
  apr_hash_set(ds->tokens, token, APR_HASH_KEY_STRING, NULL);
 
528
  apr_pool_destroy(entry->pool);
 
529
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
530
  return SVN_NO_ERROR;
 
531
}
 
532
 
 
533
static svn_error_t *ra_svn_handle_add_file(svn_ra_svn_conn_t *conn,
 
534
                                           apr_pool_t *pool,
 
535
                                           apr_array_header_t *params,
 
536
                                           void *baton)
 
537
{
 
538
  ra_svn_driver_state_t *ds = baton;
 
539
  const char *path, *token, *file_token, *copy_path;
 
540
  svn_revnum_t copy_rev;
 
541
  ra_svn_token_entry_t *entry, *file_entry;
 
542
  apr_pool_t *subpool;
 
543
 
 
544
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "ccc(?cr)", &path, &token,
 
545
                                 &file_token, &copy_path, &copy_rev));
 
546
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
547
 
 
548
  /* File may outlive parent directory, so use ds->pool here. */
 
549
  subpool = svn_pool_create(ds->pool);
 
550
  path = svn_path_canonicalize(path, pool);
 
551
  if (copy_path)
 
552
    copy_path = svn_path_canonicalize(copy_path, pool);
 
553
  file_entry = store_token(ds, NULL, file_token, subpool);
 
554
  file_entry->err = ds->editor->add_file(path, entry->baton, copy_path,
 
555
                                         copy_rev, subpool,
 
556
                                         &file_entry->baton);
 
557
  return SVN_NO_ERROR;
 
558
}
 
559
 
 
560
static svn_error_t *ra_svn_handle_open_file(svn_ra_svn_conn_t *conn,
 
561
                                            apr_pool_t *pool,
 
562
                                            apr_array_header_t *params,
 
563
                                            void *baton)
 
564
{
 
565
  ra_svn_driver_state_t *ds = baton;
 
566
  const char *path, *token, *file_token;
 
567
  svn_revnum_t rev;
 
568
  ra_svn_token_entry_t *entry, *file_entry;
 
569
  apr_pool_t *subpool;
 
570
 
 
571
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "ccc(?r)", &path, &token,
 
572
                                 &file_token, &rev));
 
573
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
574
 
 
575
  /* File may outlive parent directory, so use ds->pool here. */
 
576
  subpool = svn_pool_create(ds->pool);
 
577
  path = svn_path_canonicalize(path, pool);
 
578
  file_entry = store_token(ds, NULL, file_token, subpool);
 
579
  file_entry->err = ds->editor->open_file(path, entry->baton, rev, subpool,
 
580
                                          &file_entry->baton);
 
581
  return SVN_NO_ERROR;
 
582
}
 
583
 
 
584
static svn_error_t *ra_svn_handle_apply_textdelta(svn_ra_svn_conn_t *conn,
 
585
                                                  apr_pool_t *pool,
 
586
                                                  apr_array_header_t *params,
 
587
                                                  void *baton)
 
588
{
 
589
  ra_svn_driver_state_t *ds = baton;
 
590
  const char *token;
 
591
  ra_svn_token_entry_t *entry;
 
592
  svn_txdelta_window_handler_t wh;
 
593
  void *wh_baton;
 
594
  svn_stream_t *stream;
 
595
  apr_pool_t *subpool;
 
596
  svn_ra_svn_item_t *item;
 
597
  char *base_checksum;
 
598
 
 
599
  /* Parse arguments and look up the token. */
 
600
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?c)",
 
601
                                 &token, &base_checksum));
 
602
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
603
 
 
604
  if (!entry->err)
 
605
    entry->err = ds->editor->apply_textdelta(entry->baton, base_checksum, pool,
 
606
                                             &wh, &wh_baton);
 
607
 
 
608
  stream = svn_txdelta_parse_svndiff(wh, wh_baton, TRUE, entry->pool);
 
609
  subpool = svn_pool_create(entry->pool);
 
610
  while (1)
 
611
    {
 
612
      apr_pool_clear(subpool);
 
613
      SVN_ERR(svn_ra_svn_read_item(conn, subpool, &item));
 
614
      if (item->kind != SVN_RA_SVN_STRING)
 
615
        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
 
616
                                _("Non-string as part of text delta"));
 
617
      if (item->u.string->len == 0)
 
618
          break;
 
619
      if (!entry->err)
 
620
        entry->err = svn_stream_write(stream, item->u.string->data,
 
621
                                      &item->u.string->len);
 
622
    }
 
623
  if (!entry->err)
 
624
    entry->err = svn_stream_close(stream);
 
625
  apr_pool_destroy(subpool);
 
626
  return SVN_NO_ERROR;
 
627
}
 
628
 
 
629
static svn_error_t *ra_svn_handle_change_file_prop(svn_ra_svn_conn_t *conn,
 
630
                                                   apr_pool_t *pool,
 
631
                                                   apr_array_header_t *params,
 
632
                                                   void *baton)
 
633
{
 
634
  ra_svn_driver_state_t *ds = baton;
 
635
  const char *token, *name;
 
636
  svn_string_t *value;
 
637
  ra_svn_token_entry_t *entry;
 
638
 
 
639
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "cc(?s)", &token, &name,
 
640
                                 &value));
 
641
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
642
  if (!entry->err)
 
643
    entry->err = ds->editor->change_file_prop(entry->baton, name, value,
 
644
                                              entry->pool);
 
645
  return SVN_NO_ERROR;
 
646
}
 
647
 
 
648
static svn_error_t *ra_svn_handle_close_file(svn_ra_svn_conn_t *conn,
 
649
                                             apr_pool_t *pool,
 
650
                                             apr_array_header_t *params,
 
651
                                             void *baton)
 
652
{
 
653
  ra_svn_driver_state_t *ds = baton;
 
654
  const char *token;
 
655
  ra_svn_token_entry_t *entry;
 
656
  const char *text_checksum;
 
657
 
 
658
  /* Parse arguments and look up the file token. */
 
659
  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?c)",
 
660
                                 &token, &text_checksum));
 
661
  SVN_ERR(lookup_token(ds, token, &entry, pool));
 
662
 
 
663
  /* Return any delayed errors. */
 
664
  apr_pool_cleanup_kill(entry->pool, entry, clear_token_err);
 
665
  SVN_CMD_ERR(entry->err);
 
666
 
 
667
  /* Close the file and destroy the baton. */
 
668
  SVN_CMD_ERR(ds->editor->close_file(entry->baton, text_checksum, pool));
 
669
  apr_hash_set(ds->tokens, token, APR_HASH_KEY_STRING, NULL);
 
670
  apr_pool_destroy(entry->pool);
 
671
  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
 
672
  return SVN_NO_ERROR;
 
673
}
 
674
 
 
675
static svn_error_t *ra_svn_handle_close_edit(svn_ra_svn_conn_t *conn,
 
676
                                             apr_pool_t *pool,
 
677
                                             apr_array_header_t *params,
 
678
                                             void *baton)
 
679
{
 
680
  ra_svn_driver_state_t *ds = baton;
 
681
  svn_error_t *err;
 
682
 
 
683
  err = ds->editor->close_edit(ds->edit_baton, pool);
 
684
  if (ds->aborted)
 
685
    *ds->aborted = (err != SVN_NO_ERROR);
 
686
  SVN_CMD_ERR(err);
 
687
  return svn_ra_svn_write_cmd_response(conn, pool, "");
 
688
}
 
689
 
 
690
static svn_error_t *ra_svn_handle_abort_edit(svn_ra_svn_conn_t *conn,
 
691
                                             apr_pool_t *pool,
 
692
                                             apr_array_header_t *params,
 
693
                                             void *baton)
 
694
{
 
695
  ra_svn_driver_state_t *ds = baton;
 
696
 
 
697
  if (ds->aborted)
 
698
    *ds->aborted = TRUE;
 
699
  SVN_CMD_ERR(ds->editor->abort_edit(ds->edit_baton, pool));
 
700
  return svn_ra_svn_write_cmd_response(conn, pool, "");
 
701
}
 
702
 
 
703
static const svn_ra_svn_cmd_entry_t ra_svn_edit_commands[] = {
 
704
  { "target-rev",       ra_svn_handle_target_rev },
 
705
  { "open-root",        ra_svn_handle_open_root },
 
706
  { "delete-entry",     ra_svn_handle_delete_entry },
 
707
  { "add-dir",          ra_svn_handle_add_dir },
 
708
  { "open-dir",         ra_svn_handle_open_dir },
 
709
  { "change-dir-prop",  ra_svn_handle_change_dir_prop },
 
710
  { "close-dir",        ra_svn_handle_close_dir },
 
711
  { "add-file",         ra_svn_handle_add_file },
 
712
  { "open-file",        ra_svn_handle_open_file },
 
713
  { "apply-textdelta",  ra_svn_handle_apply_textdelta },
 
714
  { "change-file-prop", ra_svn_handle_change_file_prop },
 
715
  { "close-file",       ra_svn_handle_close_file },
 
716
  { "close-edit",       ra_svn_handle_close_edit, TRUE },
 
717
  { "abort-edit",       ra_svn_handle_abort_edit, TRUE },
 
718
  { NULL }
 
719
};
 
720
 
 
721
svn_error_t *svn_ra_svn_drive_editor(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
 
722
                                     const svn_delta_editor_t *editor,
 
723
                                     void *edit_baton,
 
724
                                     svn_boolean_t *aborted)
 
725
{
 
726
  ra_svn_driver_state_t state;
 
727
 
 
728
  if (svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_EDIT_PIPELINE))
 
729
    return svn_ra_svn__drive_editorp(conn, pool, editor, edit_baton, aborted);
 
730
 
 
731
  state.editor = editor;
 
732
  state.edit_baton = edit_baton;
 
733
  state.tokens = apr_hash_make(pool);
 
734
  state.aborted = aborted;
 
735
  state.pool = pool;
 
736
  return svn_ra_svn_handle_commands(conn, pool, ra_svn_edit_commands, &state);
 
737
}