~ubuntu-branches/ubuntu/trusty/subversion/trusty-proposed

« back to all changes in this revision

Viewing changes to subversion/libsvn_fs_base/lock.c

  • Committer: Package Import Robot
  • Author(s): Andy Whitcroft
  • Date: 2012-06-21 15:36:36 UTC
  • mfrom: (0.4.13 sid)
  • Revision ID: package-import@ubuntu.com-20120621153636-amqqmuidgwgxz1ly
Tags: 1.7.5-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Create pot file on build.
  - Build a python-subversion-dbg package.
  - Build-depend on python-dbg.
  - Build-depend on default-jre-headless/-jdk.
  - Do not apply java-build patch.
  - debian/rules: Manually create the doxygen output directory, otherwise
    we get weird build failures when running parallel builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* lock.c :  functions for manipulating filesystem locks.
2
2
 *
3
3
 * ====================================================================
4
 
 * Copyright (c) 2000-2007 CollabNet.  All rights reserved.
5
 
 *
6
 
 * This software is licensed as described in the file COPYING, which
7
 
 * you should have received as part of this distribution.  The terms
8
 
 * are also available at http://subversion.tigris.org/license-1.html.
9
 
 * If newer versions of this license are posted there, you may use a
10
 
 * newer version instead, at your option.
11
 
 *
12
 
 * This software consists of voluntary contributions made by many
13
 
 * individuals.  For exact contribution history, see the revision
14
 
 * history and logs, available at http://subversion.tigris.org/.
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
15
20
 * ====================================================================
16
21
 */
17
22
 
28
33
#include "err.h"
29
34
#include "bdb/locks-table.h"
30
35
#include "bdb/lock-tokens-table.h"
 
36
#include "util/fs_skels.h"
31
37
#include "../libsvn_fs/fs-loader.h"
32
38
#include "private/svn_fs_util.h"
33
39
 
80
86
  struct lock_args *args = baton;
81
87
  svn_node_kind_t kind = svn_node_file;
82
88
  svn_lock_t *existing_lock;
83
 
  const char *fs_username;
84
89
  svn_lock_t *lock;
85
90
 
86
91
  SVN_ERR(svn_fs_base__get_path_kind(&kind, args->path, trail, trail->pool));
88
93
  /* Until we implement directory locks someday, we only allow locks
89
94
     on files or non-existent paths. */
90
95
  if (kind == svn_node_dir)
91
 
    return SVN_FS__ERR_NOT_FILE(trail->fs, args->path);
 
96
    return SVN_FS__ERR_NOT_FILE(trail->fs, args->path, trail->pool);
92
97
 
93
98
  /* While our locking implementation easily supports the locking of
94
99
     nonexistent paths, we deliberately choose not to allow such madness. */
95
100
  if (kind == svn_node_none)
96
 
    return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
97
 
                             "Path '%s' doesn't exist in HEAD revision",
98
 
                             args->path);
 
101
    {
 
102
      if (SVN_IS_VALID_REVNUM(args->current_rev))
 
103
        return svn_error_createf(
 
104
          SVN_ERR_FS_OUT_OF_DATE, NULL,
 
105
          _("Path '%s' doesn't exist in HEAD revision"),
 
106
          args->path);
 
107
      else
 
108
        return svn_error_createf(
 
109
          SVN_ERR_FS_NOT_FOUND, NULL,
 
110
          _("Path '%s' doesn't exist in HEAD revision"),
 
111
          args->path);
 
112
    }
99
113
 
100
114
  /* There better be a username attached to the fs. */
101
115
  if (!trail->fs->access_ctx || !trail->fs->access_ctx->username)
102
 
    return SVN_FS__ERR_NO_USER(trail->fs);
103
 
  else
104
 
    fs_username = trail->fs->access_ctx->username; /* for convenience */
 
116
    return SVN_FS__ERR_NO_USER(trail->fs, trail->pool);
105
117
 
106
118
  /* Is the caller attempting to lock an out-of-date working file? */
107
119
  if (SVN_IS_VALID_REVNUM(args->current_rev))
167
179
        {
168
180
          /* Sorry, the path is already locked. */
169
181
          return SVN_FS__ERR_PATH_ALREADY_LOCKED(trail->fs,
170
 
                                                      existing_lock);
 
182
                                                 existing_lock,
 
183
                                                 trail->pool);
171
184
        }
172
185
      else
173
186
        {
238
251
     generate a URI that matches the DAV RFC.  We could change this to
239
252
     some other URI scheme someday, if we wish. */
240
253
  *token = apr_pstrcat(pool, "opaquelocktoken:",
241
 
                       svn_uuid_generate(pool), NULL);
 
254
                       svn_uuid_generate(pool), (char *)NULL);
242
255
  return SVN_NO_ERROR;
243
256
}
244
257
 
269
282
      if (args->token == NULL)
270
283
        return svn_fs_base__err_no_lock_token(trail->fs, args->path);
271
284
      else if (strcmp(lock_token, args->token) != 0)
272
 
        return SVN_FS__ERR_NO_SUCH_LOCK(trail->fs, args->path);
 
285
        return SVN_FS__ERR_NO_SUCH_LOCK(trail->fs, args->path, trail->pool);
273
286
 
274
287
      SVN_ERR(svn_fs_bdb__lock_get(&lock, trail->fs, lock_token,
275
288
                                   trail, trail->pool));
276
289
 
277
290
      /* There better be a username attached to the fs. */
278
291
      if (!trail->fs->access_ctx || !trail->fs->access_ctx->username)
279
 
        return SVN_FS__ERR_NO_USER(trail->fs);
 
292
        return SVN_FS__ERR_NO_USER(trail->fs, trail->pool);
280
293
 
281
294
      /* And that username better be the same as the lock's owner. */
282
295
      if (strcmp(trail->fs->access_ctx->username, lock->owner) != 0)
283
 
        return SVN_FS__ERR_LOCK_OWNER_MISMATCH
284
 
          (trail->fs,
 
296
        return SVN_FS__ERR_LOCK_OWNER_MISMATCH(
 
297
           trail->fs,
285
298
           trail->fs->access_ctx->username,
286
 
           lock->owner);
 
299
           lock->owner,
 
300
           trail->pool);
287
301
    }
288
302
 
289
303
  /* Remove a row from each of the locking tables. */
346
360
  else
347
361
    SVN_ERR(err);
348
362
 
349
 
  return err;
 
363
  return svn_error_trace(err);
350
364
}
351
365
 
352
366
 
381
395
  return svn_fs_base__retry_txn(fs, txn_body_get_lock, &args, FALSE, pool);
382
396
}
383
397
 
 
398
/* Implements `svn_fs_get_locks_callback_t', spooling lock information
 
399
   to disk as the filesystem provides it.  BATON is an 'apr_file_t *'
 
400
   object pointing to open, writable spool file.  We'll write the
 
401
   spool file with a format like so:
 
402
 
 
403
      SKEL1_LEN "\n" SKEL1 "\n" SKEL2_LEN "\n" SKEL2 "\n" ...
 
404
 
 
405
   where each skel is a lock skel (the same format we use to store
 
406
   locks in the `locks' table). */
 
407
static svn_error_t *
 
408
spool_locks_info(void *baton,
 
409
                 svn_lock_t *lock,
 
410
                 apr_pool_t *pool)
 
411
{
 
412
  svn_skel_t *lock_skel;
 
413
  apr_file_t *spool_file = (apr_file_t *)baton;
 
414
  const char *skel_len;
 
415
  svn_stringbuf_t *skel_buf;
 
416
 
 
417
  SVN_ERR(svn_fs_base__unparse_lock_skel(&lock_skel, lock, pool));
 
418
  skel_buf = svn_skel__unparse(lock_skel, pool);
 
419
  skel_len = apr_psprintf(pool, "%" APR_SIZE_T_FMT "\n", skel_buf->len);
 
420
  SVN_ERR(svn_io_file_write_full(spool_file, skel_len, strlen(skel_len),
 
421
                                 NULL, pool));
 
422
  SVN_ERR(svn_io_file_write_full(spool_file, skel_buf->data,
 
423
                                 skel_buf->len, NULL, pool));
 
424
  return svn_io_file_write_full(spool_file, "\n", 1, NULL, pool);
 
425
}
 
426
 
384
427
 
385
428
struct locks_get_args
386
429
{
387
430
  const char *path;
388
 
  svn_fs_get_locks_callback_t get_locks_func;
389
 
  void *get_locks_baton;
 
431
  svn_depth_t depth;
 
432
  apr_file_t *spool_file;
390
433
};
391
434
 
392
435
 
394
437
txn_body_get_locks(void *baton, trail_t *trail)
395
438
{
396
439
  struct locks_get_args *args = baton;
397
 
  return svn_fs_bdb__locks_get(trail->fs, args->path,
398
 
                               args->get_locks_func, args->get_locks_baton,
 
440
  return svn_fs_bdb__locks_get(trail->fs, args->path, args->depth,
 
441
                               spool_locks_info, args->spool_file,
399
442
                               trail, trail->pool);
400
443
}
401
444
 
403
446
svn_error_t *
404
447
svn_fs_base__get_locks(svn_fs_t *fs,
405
448
                       const char *path,
 
449
                       svn_depth_t depth,
406
450
                       svn_fs_get_locks_callback_t get_locks_func,
407
451
                       void *get_locks_baton,
408
452
                       apr_pool_t *pool)
409
453
{
410
454
  struct locks_get_args args;
 
455
  apr_off_t offset = 0;
 
456
  svn_stream_t *stream;
 
457
  svn_stringbuf_t *buf;
 
458
  svn_boolean_t eof;
 
459
  apr_pool_t *iterpool = svn_pool_create(pool);
411
460
 
412
461
  SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
462
 
413
463
  args.path = svn_fs__canonicalize_abspath(path, pool);
414
 
  args.get_locks_func = get_locks_func;
415
 
  args.get_locks_baton = get_locks_baton;
416
 
  return svn_fs_base__retry_txn(fs, txn_body_get_locks, &args, FALSE, pool);
 
464
  args.depth = depth;
 
465
  SVN_ERR(svn_io_open_uniquely_named(&(args.spool_file), NULL, NULL, NULL,
 
466
                                     NULL, svn_io_file_del_on_close,
 
467
                                     pool, pool));
 
468
  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_get_locks, &args, FALSE, pool));
 
469
 
 
470
  /* Rewind the spool file, then re-read it, calling GET_LOCKS_FUNC(). */
 
471
  SVN_ERR(svn_io_file_seek(args.spool_file, APR_SET, &offset, pool));
 
472
  stream = svn_stream_from_aprfile2(args.spool_file, FALSE, pool);
 
473
 
 
474
  while (1)
 
475
    {
 
476
      apr_size_t len, skel_len;
 
477
      char c, *end, *skel_buf;
 
478
      svn_skel_t *lock_skel;
 
479
      svn_lock_t *lock;
 
480
 
 
481
      svn_pool_clear(iterpool);
 
482
 
 
483
      /* Read a skel length line and parse it for the skel's length.  */
 
484
      SVN_ERR(svn_stream_readline(stream, &buf, "\n", &eof, iterpool));
 
485
      if (eof)
 
486
        break;
 
487
      skel_len = (size_t) strtoul(buf->data, &end, 10);
 
488
      if (skel_len == (size_t) ULONG_MAX || *end != '\0')
 
489
        return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL);
 
490
 
 
491
      /* Now read that much into a buffer. */
 
492
      skel_buf = apr_palloc(pool, skel_len + 1);
 
493
      SVN_ERR(svn_stream_read(stream, skel_buf, &skel_len));
 
494
      skel_buf[skel_len] = '\0';
 
495
 
 
496
      /* Read the extra newline that follows the skel. */
 
497
      len = 1;
 
498
      SVN_ERR(svn_stream_read(stream, &c, &len));
 
499
      if (c != '\n')
 
500
        return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL);
 
501
 
 
502
      /* Parse the skel into a lock, and notify the caller. */
 
503
      lock_skel = svn_skel__parse(skel_buf, skel_len, iterpool);
 
504
      SVN_ERR(svn_fs_base__parse_lock_skel(&lock, lock_skel, iterpool));
 
505
      SVN_ERR(get_locks_func(get_locks_baton, lock, iterpool));
 
506
    }
 
507
 
 
508
  SVN_ERR(svn_stream_close(stream));
 
509
  svn_pool_destroy(iterpool);
 
510
  return SVN_NO_ERROR;
417
511
}
418
512
 
419
513
 
444
538
  else if (strcmp(fs->access_ctx->username, lock->owner) != 0)
445
539
    return svn_error_createf
446
540
      (SVN_ERR_FS_LOCK_OWNER_MISMATCH, NULL,
447
 
       _("User %s does not own lock on path '%s' (currently locked by %s)"),
 
541
       _("User '%s' does not own lock on path '%s' (currently locked by '%s')"),
448
542
       fs->access_ctx->username, lock->path, lock->owner);
449
543
 
450
544
  else if (apr_hash_get(fs->access_ctx->lock_tokens, lock->token,
479
573
  if (recurse)
480
574
    {
481
575
      /* Discover all locks at or below the path. */
482
 
      SVN_ERR(svn_fs_bdb__locks_get(trail->fs, path, get_locks_callback,
 
576
      SVN_ERR(svn_fs_bdb__locks_get(trail->fs, path, svn_depth_infinity,
 
577
                                    get_locks_callback,
483
578
                                    trail->fs, trail, pool));
484
579
    }
485
580
  else