~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_neon/lock.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * lock.c :  routines for managing lock states in the DAV server
3
 
 *
4
 
 * ====================================================================
5
 
 *    Licensed to the Apache Software Foundation (ASF) under one
6
 
 *    or more contributor license agreements.  See the NOTICE file
7
 
 *    distributed with this work for additional information
8
 
 *    regarding copyright ownership.  The ASF licenses this file
9
 
 *    to you under the Apache License, Version 2.0 (the
10
 
 *    "License"); you may not use this file except in compliance
11
 
 *    with the License.  You may obtain a copy of the License at
12
 
 *
13
 
 *      http://www.apache.org/licenses/LICENSE-2.0
14
 
 *
15
 
 *    Unless required by applicable law or agreed to in writing,
16
 
 *    software distributed under the License is distributed on an
17
 
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18
 
 *    KIND, either express or implied.  See the License for the
19
 
 *    specific language governing permissions and limitations
20
 
 *    under the License.
21
 
 * ====================================================================
22
 
 */
23
 
 
24
 
 
25
 
 
26
 
#define APR_WANT_STRFUNC
27
 
#include <apr_want.h>
28
 
#include <apr_xml.h>
29
 
 
30
 
#include "svn_error.h"
31
 
#include "svn_pools.h"
32
 
#include "svn_ra.h"
33
 
#include "../libsvn_ra/ra_loader.h"
34
 
#include "svn_path.h"
35
 
#include "svn_string.h"
36
 
#include "svn_time.h"
37
 
#include "svn_private_config.h"
38
 
 
39
 
#include "ra_neon.h"
40
 
 
41
 
static const svn_ra_neon__xml_elm_t lock_elements[] =
42
 
{
43
 
  /* lockdiscovery elements */
44
 
  { "DAV:", "response", ELEM_response, 0 },
45
 
  { "DAV:", "propstat", ELEM_propstat, 0 },
46
 
  { "DAV:", "status", ELEM_status, SVN_RA_NEON__XML_CDATA },
47
 
  /* extend lockdiscovery elements here;
48
 
     ### Remember to update do_lock() when you change the number of
49
 
     elements here: it contains a hard reference to the next element. */
50
 
 
51
 
  /* lock and lockdiscovery elements */
52
 
  { "DAV:", "prop", ELEM_prop, 0 },
53
 
  { "DAV:", "lockdiscovery", ELEM_lock_discovery, 0 },
54
 
  { "DAV:", "activelock", ELEM_lock_activelock, 0 },
55
 
  { "DAV:", "locktype", ELEM_lock_type, SVN_RA_NEON__XML_CDATA },
56
 
  { "DAV:", "lockscope", ELEM_lock_scope, SVN_RA_NEON__XML_CDATA },
57
 
  { "DAV:", "depth", ELEM_lock_depth, SVN_RA_NEON__XML_CDATA },
58
 
  { "DAV:", "owner", ELEM_lock_owner, SVN_RA_NEON__XML_COLLECT },
59
 
  { "DAV:", "timeout", ELEM_lock_timeout, SVN_RA_NEON__XML_CDATA },
60
 
  { "DAV:", "locktoken", ELEM_lock_token, 0 },
61
 
  { "DAV:", "href", ELEM_href, SVN_RA_NEON__XML_CDATA },
62
 
  { "", "", ELEM_unknown, SVN_RA_NEON__XML_COLLECT },
63
 
  /* extend lock elements here */
64
 
 
65
 
  { NULL }
66
 
};
67
 
 
68
 
typedef struct lock_baton_t
69
 
{
70
 
  svn_stringbuf_t *cdata;
71
 
  apr_pool_t *pool;
72
 
  const svn_ra_neon__xml_elm_t *xml_table;
73
 
 
74
 
  /* lockdiscovery fields */
75
 
  svn_stringbuf_t *href;
76
 
  svn_stringbuf_t *status_line;
77
 
 
78
 
  /* lock and lockdiscovery fields */
79
 
  int parent;
80
 
  svn_stringbuf_t *owner;
81
 
  svn_stringbuf_t *timeout;
82
 
  svn_stringbuf_t *depth;
83
 
  svn_stringbuf_t *token;
84
 
} lock_baton_t;
85
 
 
86
 
static svn_error_t *
87
 
lock_start_element(int *elem, void *baton, int parent,
88
 
                   const char *nspace, const char *name, const char **atts)
89
 
{
90
 
  lock_baton_t *b = baton;
91
 
  const svn_ra_neon__xml_elm_t *elm =
92
 
    svn_ra_neon__lookup_xml_elem(b->xml_table, nspace, name);
93
 
 
94
 
  if (! elm)
95
 
    {
96
 
      *elem = NE_XML_DECLINE;
97
 
      return SVN_NO_ERROR;
98
 
    }
99
 
 
100
 
  /* collect interesting element contents */
101
 
  /* owner, href inside locktoken, depth, timeout */
102
 
  switch (elm->id)
103
 
    {
104
 
    case ELEM_lock_owner:
105
 
    case ELEM_lock_timeout:
106
 
    case ELEM_lock_depth:
107
 
    case ELEM_status:
108
 
      b->cdata = svn_stringbuf_create("", b->pool);
109
 
      break;
110
 
 
111
 
    case ELEM_href:
112
 
      if (parent == ELEM_lock_token
113
 
          || parent == ELEM_response)
114
 
        b->cdata = svn_stringbuf_create("", b->pool);
115
 
      break;
116
 
 
117
 
    default:
118
 
      b->cdata = NULL;
119
 
    }
120
 
 
121
 
  b->parent = parent;
122
 
  *elem = elm->id;
123
 
  return SVN_NO_ERROR;
124
 
}
125
 
 
126
 
static svn_error_t *
127
 
lock_end_element(void *baton, int state, const char *nspace, const char *name)
128
 
{
129
 
  lock_baton_t *b = baton;
130
 
 
131
 
  if (b->cdata)
132
 
    switch (state)
133
 
      {
134
 
      case ELEM_lock_owner:
135
 
        b->owner = b->cdata;
136
 
        break;
137
 
 
138
 
      case ELEM_lock_timeout:
139
 
        b->timeout = b->cdata;
140
 
        break;
141
 
 
142
 
      case ELEM_lock_depth:
143
 
        b->depth = b->cdata;
144
 
        break;
145
 
 
146
 
      case ELEM_href:
147
 
        if (b->parent == ELEM_lock_token)
148
 
          b->token = b->cdata;
149
 
        else
150
 
          b->href = b->cdata;
151
 
        break;
152
 
 
153
 
      case ELEM_status:
154
 
        b->status_line = b->cdata;
155
 
        break;
156
 
      }
157
 
 
158
 
  b->cdata = NULL;
159
 
 
160
 
  return SVN_NO_ERROR;
161
 
}
162
 
 
163
 
static svn_error_t *
164
 
lock_cdata(void *baton, int state, const char *cdata, size_t len)
165
 
{
166
 
  lock_baton_t *b = baton;
167
 
 
168
 
  if (b->cdata)
169
 
    svn_stringbuf_appendbytes(b->cdata, cdata, len);
170
 
 
171
 
  return SVN_NO_ERROR;
172
 
}
173
 
 
174
 
 
175
 
static svn_error_t *
176
 
lock_from_baton(svn_lock_t **lock,
177
 
                svn_ra_neon__request_t *req,
178
 
                const char *path,
179
 
                lock_baton_t *lrb, apr_pool_t *pool)
180
 
{
181
 
  const char *val;
182
 
  svn_lock_t *lck = svn_lock_create(pool);
183
 
 
184
 
  if (lrb->token)
185
 
    lck->token = lrb->token->data;
186
 
  else
187
 
    {
188
 
      /* No lock */
189
 
      *lock = NULL;
190
 
      return SVN_NO_ERROR;
191
 
    }
192
 
 
193
 
  val = ne_get_response_header(req->ne_req, SVN_DAV_CREATIONDATE_HEADER);
194
 
  if (val)
195
 
    SVN_ERR_W(svn_time_from_cstring(&(lck->creation_date), val, pool),
196
 
              _("Invalid creation date header value in response."));
197
 
 
198
 
  val = ne_get_response_header(req->ne_req, SVN_DAV_LOCK_OWNER_HEADER);
199
 
  if (val)
200
 
    lck->owner = apr_pstrdup(pool, val);
201
 
  if (lrb->owner)
202
 
    lck->comment = lrb->owner->data;
203
 
  if (path)
204
 
    lck->path = path;
205
 
  if (lrb->timeout)
206
 
    {
207
 
      const char *timeout_str = lrb->timeout->data;
208
 
 
209
 
      if (strcmp(timeout_str, "Infinite") != 0)
210
 
        {
211
 
          if (strncmp("Second-", timeout_str, strlen("Second-")) == 0)
212
 
            {
213
 
              int time_offset;
214
 
 
215
 
              SVN_ERR(svn_cstring_atoi(&time_offset, &(timeout_str[7])));
216
 
              lck->expiration_date = lck->creation_date
217
 
                + apr_time_from_sec(time_offset);
218
 
            }
219
 
          else
220
 
            return svn_error_create(SVN_ERR_RA_DAV_RESPONSE_HEADER_BADNESS,
221
 
                                    NULL, _("Invalid timeout value"));
222
 
        }
223
 
      else
224
 
        lck->expiration_date = 0;
225
 
    }
226
 
  *lock = lck;
227
 
 
228
 
  return SVN_NO_ERROR;
229
 
}
230
 
 
231
 
static svn_error_t *
232
 
do_lock(svn_lock_t **lock,
233
 
        svn_ra_session_t *session,
234
 
        const char *path,
235
 
        const char *comment,
236
 
        svn_boolean_t force,
237
 
        svn_revnum_t current_rev,
238
 
        apr_pool_t *pool)
239
 
{
240
 
  svn_ra_neon__request_t *req;
241
 
  svn_stringbuf_t *body;
242
 
  ne_uri uri;
243
 
  int code;
244
 
  const char *url;
245
 
  const char *fs_path;
246
 
  ne_xml_parser *lck_parser;
247
 
  svn_ra_neon__session_t *ras = session->priv;
248
 
  lock_baton_t *lrb = apr_pcalloc(pool, sizeof(*lrb));
249
 
  apr_hash_t *extra_headers;
250
 
  svn_error_t *err = SVN_NO_ERROR;
251
 
 
252
 
  /* To begin, we convert the incoming path into an absolute fs-path. */
253
 
  url = svn_path_url_add_component2(ras->url->data, path, pool);
254
 
  SVN_ERR(svn_ra_neon__get_baseline_info(NULL, &fs_path, NULL, ras,
255
 
                                         url, SVN_INVALID_REVNUM, pool));
256
 
 
257
 
  if (ne_uri_parse(url, &uri) != 0)
258
 
    {
259
 
      ne_uri_free(&uri);
260
 
      return svn_error_createf(SVN_ERR_RA_DAV_CREATING_REQUEST, NULL,
261
 
                               _("Failed to parse URI '%s'"), url);
262
 
    }
263
 
 
264
 
  SVN_ERR(svn_ra_neon__request_create(&req, ras, "LOCK", uri.path, pool));
265
 
  ne_uri_free(&uri);
266
 
 
267
 
  lrb->pool = pool;
268
 
  lrb->xml_table = &(lock_elements[3]);
269
 
  lck_parser = svn_ra_neon__xml_parser_create
270
 
    (req, ne_accept_2xx,
271
 
     lock_start_element, lock_cdata, lock_end_element, lrb);
272
 
 
273
 
  body = svn_stringbuf_createf
274
 
    (req->pool,
275
 
     "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" DEBUG_CR
276
 
     "<D:lockinfo xmlns:D=\"DAV:\">" DEBUG_CR
277
 
     " <D:lockscope><D:exclusive /></D:lockscope>" DEBUG_CR
278
 
     " <D:locktype><D:write /></D:locktype>" DEBUG_CR
279
 
     "%s" /* maybe owner */
280
 
     "</D:lockinfo>",
281
 
     comment ? apr_pstrcat(pool,
282
 
                           "<D:owner>",
283
 
                           apr_xml_quote_string(pool, comment, 0),
284
 
                           "</D:owner>",
285
 
                           (char *)NULL)
286
 
             : "");
287
 
 
288
 
  extra_headers = apr_hash_make(req->pool);
289
 
  svn_ra_neon__set_header(extra_headers, "Depth", "0");
290
 
  svn_ra_neon__set_header(extra_headers, "Timeout", "Infinite");
291
 
  svn_ra_neon__set_header(extra_headers, "Content-Type",
292
 
                         "text/xml; charset=\"utf-8\"");
293
 
  if (force)
294
 
    svn_ra_neon__set_header(extra_headers, SVN_DAV_OPTIONS_HEADER,
295
 
                            SVN_DAV_OPTION_LOCK_STEAL);
296
 
  if (SVN_IS_VALID_REVNUM(current_rev))
297
 
    svn_ra_neon__set_header(extra_headers, SVN_DAV_VERSION_NAME_HEADER,
298
 
                            apr_psprintf(req->pool, "%ld", current_rev));
299
 
 
300
 
  err = svn_ra_neon__request_dispatch(&code, req, extra_headers, body->data,
301
 
                                      200, 0, pool);
302
 
  if (err)
303
 
    goto cleanup;
304
 
 
305
 
  err = svn_ra_neon__check_parse_error("LOCK", lck_parser, url);
306
 
  if (err)
307
 
    goto cleanup;
308
 
 
309
 
  /*###FIXME: we never verified whether we have received back the type
310
 
    of lock we requested: was it shared/exclusive? was it write/otherwise?
311
 
    How many did we get back? Only one? */
312
 
  err = lock_from_baton(lock, req, fs_path, lrb, pool);
313
 
 
314
 
 cleanup:
315
 
  /* 405 == Method Not Allowed (Occurs when trying to lock a working
316
 
     copy path which no longer exists at HEAD in the repository. */
317
 
  if (code == 405)
318
 
    {
319
 
      svn_error_clear(err);
320
 
      err = svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL,
321
 
                              _("Lock request failed: %d %s"),
322
 
                              code, req->code_desc);
323
 
    }
324
 
  svn_ra_neon__request_destroy(req);
325
 
 
326
 
  return err;
327
 
}
328
 
 
329
 
svn_error_t *
330
 
svn_ra_neon__lock(svn_ra_session_t *session,
331
 
                  apr_hash_t *path_revs,
332
 
                  const char *comment,
333
 
                  svn_boolean_t force,
334
 
                  svn_ra_lock_callback_t lock_func,
335
 
                  void *lock_baton,
336
 
                  apr_pool_t *pool)
337
 
{
338
 
  apr_hash_index_t *hi;
339
 
  apr_pool_t *iterpool = svn_pool_create(pool);
340
 
  svn_ra_neon__session_t *ras = session->priv;
341
 
  svn_error_t *ret_err = NULL;
342
 
 
343
 
  /* ### TODO for issue 2263: Send all the locks over the wire at once.  This
344
 
     loop is just a temporary shim. */
345
 
  for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
346
 
    {
347
 
      svn_lock_t *lock;
348
 
      const void *key;
349
 
      const char *path;
350
 
      void *val;
351
 
      svn_revnum_t *revnum;
352
 
      svn_error_t *err, *callback_err = NULL;
353
 
 
354
 
      svn_pool_clear(iterpool);
355
 
 
356
 
      apr_hash_this(hi, &key, NULL, &val);
357
 
      path = key;
358
 
      revnum = val;
359
 
 
360
 
      err = do_lock(&lock, session, path, comment, force, *revnum, iterpool);
361
 
 
362
 
      if (err && !SVN_ERR_IS_LOCK_ERROR(err))
363
 
        {
364
 
          ret_err = err;
365
 
          goto departure;
366
 
        }
367
 
 
368
 
      if (lock_func)
369
 
        callback_err = lock_func(lock_baton, path, TRUE, err ? NULL : lock,
370
 
                                 err, iterpool);
371
 
 
372
 
      svn_error_clear(err);
373
 
 
374
 
      if (callback_err)
375
 
        {
376
 
          ret_err = callback_err;
377
 
          goto departure;
378
 
        }
379
 
 
380
 
    }
381
 
 
382
 
  svn_pool_destroy(iterpool);
383
 
 
384
 
 departure:
385
 
  return svn_ra_neon__maybe_store_auth_info_after_result(ret_err, ras, pool);
386
 
}
387
 
 
388
 
 
389
 
/* ###TODO for issue 2263: Send all lock tokens to the server at once. */
390
 
static svn_error_t *
391
 
do_unlock(svn_ra_session_t *session,
392
 
          const char *path,
393
 
          const char *token,
394
 
          svn_boolean_t force,
395
 
          const svn_lock_t **old_lock,
396
 
          apr_pool_t *pool)
397
 
{
398
 
  svn_ra_neon__session_t *ras = session->priv;
399
 
  const char *url;
400
 
  const char *url_path;
401
 
  ne_uri uri;
402
 
  svn_error_t *err = SVN_NO_ERROR;
403
 
 
404
 
  apr_hash_t *extra_headers = apr_hash_make(pool);
405
 
 
406
 
  if (old_lock)
407
 
    *old_lock = NULL;
408
 
 
409
 
  /* Make a neon lock structure containing token and full URL to unlock. */
410
 
  url = svn_path_url_add_component2(ras->url->data, path, pool);
411
 
  if (ne_uri_parse(url, &uri) != 0)
412
 
    {
413
 
      ne_uri_free(&uri);
414
 
      return svn_error_createf(SVN_ERR_RA_DAV_CREATING_REQUEST, NULL,
415
 
                               _("Failed to parse URI '%s'"), url);
416
 
    }
417
 
 
418
 
  url_path = apr_pstrdup(pool, uri.path);
419
 
  ne_uri_free(&uri);
420
 
  /* In the case of 'force', we might not have a token at all.
421
 
     Unfortunately, mod_dav insists on having a valid token for
422
 
     UNLOCK requests.  That means we need to fetch the token. */
423
 
  if (! token)
424
 
    {
425
 
      svn_lock_t *lock;
426
 
 
427
 
      SVN_ERR(svn_ra_neon__get_lock(session, &lock, path, pool));
428
 
      if (! lock)
429
 
        return svn_error_createf(SVN_ERR_RA_NOT_LOCKED, NULL,
430
 
                                 _("'%s' is not locked in the repository"),
431
 
                                 path);
432
 
      token = lock->token;
433
 
      if (old_lock)
434
 
        *old_lock = lock;
435
 
    }
436
 
 
437
 
  apr_hash_set(extra_headers, "Lock-Token", APR_HASH_KEY_STRING,
438
 
               apr_psprintf(pool, "<%s>", token));
439
 
  if (force)
440
 
    apr_hash_set(extra_headers, SVN_DAV_OPTIONS_HEADER, APR_HASH_KEY_STRING,
441
 
                 SVN_DAV_OPTION_LOCK_BREAK);
442
 
 
443
 
  {
444
 
    int code = 0;
445
 
 
446
 
    err = svn_ra_neon__simple_request(&code, ras, "UNLOCK", url_path,
447
 
                                      extra_headers, NULL, 204, 0, pool);
448
 
 
449
 
    if (err && ((err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
450
 
                || (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
451
 
      {
452
 
        switch (code)
453
 
          {
454
 
            case 403:
455
 
              return svn_error_createf(SVN_ERR_FS_LOCK_OWNER_MISMATCH, err,
456
 
                                       _("Unlock failed on '%s'"
457
 
                                         " (%d Forbidden)"), path, code);
458
 
            case 400:
459
 
               return svn_error_createf(SVN_ERR_FS_NO_SUCH_LOCK, err,
460
 
                                       _("No lock on path '%s'"
461
 
                                         " (%d Bad Request)"), path, code);
462
 
            default:
463
 
              break;
464
 
          }
465
 
      }
466
 
  }
467
 
  return svn_error_trace(err);
468
 
}
469
 
 
470
 
 
471
 
svn_error_t *
472
 
svn_ra_neon__unlock(svn_ra_session_t *session,
473
 
                    apr_hash_t *path_tokens,
474
 
                    svn_boolean_t force,
475
 
                    svn_ra_lock_callback_t lock_func,
476
 
                    void *lock_baton,
477
 
                    apr_pool_t *pool)
478
 
{
479
 
  apr_hash_index_t *hi;
480
 
  apr_pool_t *iterpool = svn_pool_create(pool);
481
 
  svn_ra_neon__session_t *ras = session->priv;
482
 
  svn_error_t *ret_err = NULL;
483
 
 
484
 
  /* ### TODO for issue 2263: Send all the lock tokens over the wire at once.
485
 
        This loop is just a temporary shim. */
486
 
  for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi))
487
 
    {
488
 
      const void *key;
489
 
      const char *path;
490
 
      void *val;
491
 
      const char *token;
492
 
      svn_error_t *err, *callback_err = NULL;
493
 
      const svn_lock_t *old_lock = NULL;
494
 
 
495
 
      svn_pool_clear(iterpool);
496
 
 
497
 
      apr_hash_this(hi, &key, NULL, &val);
498
 
      path = key;
499
 
      /* Since we can't store NULL values in a hash, we turn "" to
500
 
         NULL here. */
501
 
      if (strcmp(val, "") != 0)
502
 
        token = val;
503
 
      else
504
 
        token = NULL;
505
 
 
506
 
      err = do_unlock(session, path, token, force, &old_lock, iterpool);
507
 
 
508
 
      if (err && !SVN_ERR_IS_UNLOCK_ERROR(err))
509
 
        {
510
 
          ret_err = err;
511
 
          goto departure;
512
 
        }
513
 
 
514
 
      if (lock_func)
515
 
        callback_err = svn_error_trace(
516
 
                 lock_func(lock_baton, path, FALSE, old_lock, err, iterpool));
517
 
 
518
 
      svn_error_clear(err);
519
 
 
520
 
      if (callback_err)
521
 
        {
522
 
          ret_err = callback_err;
523
 
          goto departure;
524
 
        }
525
 
    }
526
 
 
527
 
  svn_pool_destroy(iterpool);
528
 
 
529
 
 departure:
530
 
  return svn_error_trace(
531
 
          svn_ra_neon__maybe_store_auth_info_after_result(ret_err, ras, pool));
532
 
}
533
 
 
534
 
 
535
 
svn_error_t *
536
 
svn_ra_neon__get_lock_internal(svn_ra_neon__session_t *ras,
537
 
                               svn_lock_t **lock,
538
 
                               const char *path,
539
 
                               apr_pool_t *pool)
540
 
{
541
 
  const char *url;
542
 
  const char *fs_path;
543
 
  svn_error_t *err;
544
 
  ne_uri uri;
545
 
  lock_baton_t *lrb = apr_pcalloc(pool, sizeof(*lrb));
546
 
  svn_ra_neon__request_t *req;
547
 
  ne_xml_parser *lck_parser;
548
 
  apr_hash_t *extra_headers;
549
 
  static const char *body =
550
 
    "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" DEBUG_CR
551
 
    "<D:propfind xmlns:D=\"DAV:\">" DEBUG_CR
552
 
    " <D:prop>" DEBUG_CR
553
 
    "  <D:lockdiscovery />" DEBUG_CR
554
 
    " </D:prop>" DEBUG_CR
555
 
    "</D:propfind>";
556
 
 
557
 
  /* To begin, we convert the incoming path into an absolute fs-path. */
558
 
  url = svn_path_url_add_component2(ras->url->data, path, pool);
559
 
 
560
 
  err = svn_ra_neon__get_baseline_info(NULL, &fs_path, NULL, ras,
561
 
                                       url, SVN_INVALID_REVNUM, pool);
562
 
  SVN_ERR(svn_ra_neon__maybe_store_auth_info_after_result(err, ras, pool));
563
 
 
564
 
  ne_uri_parse(url, &uri);
565
 
  url = apr_pstrdup(pool, uri.path);
566
 
  ne_uri_free(&uri);
567
 
 
568
 
  SVN_ERR(svn_ra_neon__request_create(&req, ras, "PROPFIND", url, pool));
569
 
 
570
 
  lrb->pool = pool;
571
 
  lrb->xml_table = lock_elements;
572
 
  lck_parser = svn_ra_neon__xml_parser_create
573
 
    (req, ne_accept_207, lock_start_element, lock_cdata, lock_end_element, lrb);
574
 
 
575
 
  extra_headers = apr_hash_make(req->pool);
576
 
  svn_ra_neon__set_header(extra_headers, "Depth", "0");
577
 
  svn_ra_neon__set_header(extra_headers, "Content-Type",
578
 
                          "text/xml; charset=\"utf-8\"");
579
 
 
580
 
  err = svn_ra_neon__request_dispatch(NULL, req, extra_headers, body,
581
 
                                      200, 207, pool);
582
 
  if (err)
583
 
    {
584
 
      err = svn_error_quick_wrap(err, _("Failed to fetch lock information"));
585
 
      goto cleanup;
586
 
    }
587
 
 
588
 
  err = svn_ra_neon__check_parse_error("PROPFIND", lck_parser, url);
589
 
  if (err)
590
 
    goto cleanup;
591
 
 
592
 
  /*###FIXME We assume here we only got one lock response. The WebDAV
593
 
    spec makes no such guarantees. How to make sure we grab the one we need? */
594
 
  err = lock_from_baton(lock, req, fs_path, lrb, pool);
595
 
 
596
 
 cleanup:
597
 
  svn_ra_neon__request_destroy(req);
598
 
  return err;
599
 
}
600
 
 
601
 
 
602
 
svn_error_t *
603
 
svn_ra_neon__get_lock(svn_ra_session_t *session,
604
 
                      svn_lock_t **lock,
605
 
                      const char *path,
606
 
                      apr_pool_t *pool)
607
 
{
608
 
  return svn_ra_neon__get_lock_internal(session->priv, lock, path, pool);
609
 
}