~svn/ubuntu/oneiric/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/libsvn_fs_fs/lock.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-12-13 17:57:16 UTC
  • mfrom: (1.1.6 upstream) (0.1.3 etch)
  • Revision ID: james.westby@ubuntu.com-20061213175716-2ysv6z4w5dpa2r2f
Tags: 1.4.2dfsg1-2ubuntu1
* Merge with Debian unstable; remaining changes:
  - Create pot file on build.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#include "svn_utf.h"
27
27
#include "svn_md5.h"
28
28
 
29
 
#include "apr_uuid.h"
30
 
#include "apr_file_io.h"
31
 
#include "apr_file_info.h"
32
 
#include "apr_md5.h"
 
29
#include <apr_uuid.h>
 
30
#include <apr_file_io.h>
 
31
#include <apr_file_info.h>
 
32
#include <apr_md5.h>
33
33
 
34
34
#include "lock.h"
35
35
#include "tree.h"
62
62
 
63
63
/* Return the MD5 hash of STR. */
64
64
static const char *
65
 
make_digest (const char *str,
66
 
             apr_pool_t *pool)
 
65
make_digest(const char *str,
 
66
            apr_pool_t *pool)
67
67
{
68
68
  unsigned char digest[APR_MD5_DIGESTSIZE];
69
69
 
70
 
  apr_md5 (digest, str, strlen(str));
71
 
  return svn_md5_digest_to_cstring_display (digest, pool);
 
70
  apr_md5(digest, str, strlen(str));
 
71
  return svn_md5_digest_to_cstring_display(digest, pool);
72
72
}
73
73
 
74
74
 
78
78
   will be allocated in POOL; KEY will not be duped.  If either KEY or VALUE
79
79
   is NULL, this function will do nothing. */
80
80
static void
81
 
hash_store (apr_hash_t *hash,
82
 
            const char *key,
83
 
            apr_ssize_t key_len,
84
 
            const char *value,
85
 
            apr_ssize_t value_len,
86
 
            apr_pool_t *pool)
 
81
hash_store(apr_hash_t *hash,
 
82
           const char *key,
 
83
           apr_ssize_t key_len,
 
84
           const char *value,
 
85
           apr_ssize_t value_len,
 
86
           apr_pool_t *pool)
87
87
{
88
88
  if (! (key && value))
89
89
    return;
90
90
  if (value_len == APR_HASH_KEY_STRING)
91
 
    value_len = strlen (value);
92
 
  apr_hash_set (hash, key, key_len, 
93
 
                svn_string_ncreate (value, value_len, pool));
 
91
    value_len = strlen(value);
 
92
  apr_hash_set(hash, key, key_len, 
 
93
               svn_string_ncreate(value, value_len, pool));
94
94
}
95
95
 
96
96
 
97
97
/* Fetch the value of KEY from HASH, returning only the cstring data
98
98
   of that value (if it exists). */
99
99
static const char *
100
 
hash_fetch (apr_hash_t *hash,
101
 
            const char *key,
102
 
            apr_pool_t *pool)
 
100
hash_fetch(apr_hash_t *hash,
 
101
           const char *key,
 
102
           apr_pool_t *pool)
103
103
{
104
 
  svn_string_t *str = apr_hash_get (hash, key, APR_HASH_KEY_STRING);
 
104
  svn_string_t *str = apr_hash_get(hash, key, APR_HASH_KEY_STRING);
105
105
  return str ? str->data : NULL;
106
106
}
107
107
 
112
112
/* Return the path of the lock/entries file for which DIGEST is the
113
113
   hashed repository relative path. */
114
114
static const char *
115
 
digest_path_from_digest (svn_fs_t *fs,
116
 
                         const char *digest,
117
 
                         apr_pool_t *pool)
 
115
digest_path_from_digest(svn_fs_t *fs,
 
116
                        const char *digest,
 
117
                        apr_pool_t *pool)
118
118
{
119
 
  return svn_path_join_many (pool, fs->path, LOCK_ROOT_DIR, 
120
 
                             apr_pstrmemdup (pool, digest, DIGEST_SUBDIR_LEN), 
121
 
                             digest, NULL);
 
119
  return svn_path_join_many(pool, fs->path, LOCK_ROOT_DIR, 
 
120
                            apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN), 
 
121
                            digest, NULL);
122
122
}
123
123
 
124
124
 
126
126
   PATH, where PATH is the path to the lock file or lock entries file
127
127
   in FS. */
128
128
static const char *
129
 
digest_path_from_path (svn_fs_t *fs,
130
 
                       const char *path,
131
 
                       apr_pool_t *pool)
 
129
digest_path_from_path(svn_fs_t *fs,
 
130
                      const char *path,
 
131
                      apr_pool_t *pool)
132
132
{
133
 
  const char *digest = make_digest (path, pool);
134
 
  return svn_path_join_many (pool, fs->path, LOCK_ROOT_DIR, 
135
 
                             apr_pstrmemdup (pool, digest, DIGEST_SUBDIR_LEN), 
136
 
                             digest, NULL);
 
133
  const char *digest = make_digest(path, pool);
 
134
  return svn_path_join_many(pool, fs->path, LOCK_ROOT_DIR, 
 
135
                            apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN), 
 
136
                            digest, NULL);
137
137
}
138
138
 
139
139
 
140
140
/* If directory PATH does not exist, create it and give it the same
141
141
   permissions as FS->path.*/
142
142
static svn_error_t *
143
 
ensure_dir_exists (const char *path,
144
 
                   svn_fs_t *fs,
145
 
                   apr_pool_t *pool)
 
143
ensure_dir_exists(const char *path,
 
144
                  svn_fs_t *fs,
 
145
                  apr_pool_t *pool)
146
146
{
147
 
  svn_error_t *err = svn_io_dir_make (path, APR_OS_DEFAULT, pool);
148
 
  if (err && APR_STATUS_IS_EEXIST (err->apr_err))
 
147
  svn_error_t *err = svn_io_dir_make(path, APR_OS_DEFAULT, pool);
 
148
  if (err && APR_STATUS_IS_EEXIST(err->apr_err))
149
149
    {
150
 
      svn_error_clear (err);
 
150
      svn_error_clear(err);
151
151
      return SVN_NO_ERROR;
152
152
    }
153
 
  SVN_ERR (err);
 
153
  SVN_ERR(err);
154
154
 
155
155
  /* We successfully created a new directory.  Dup the permissions
156
156
     from FS->path. */
157
 
  SVN_ERR (svn_fs_fs__dup_perms (path, fs->path, pool));
 
157
  SVN_ERR(svn_fs_fs__dup_perms(path, fs->path, pool));
158
158
 
159
159
  return SVN_NO_ERROR;
160
160
}
165
165
   no children) and LOCK (which may be NULL if that versioned path is
166
166
   lock itself locked).  Use POOL for all allocations. */
167
167
static svn_error_t *
168
 
write_digest_file (apr_hash_t *children,
169
 
                   svn_lock_t *lock,
170
 
                   svn_fs_t *fs,
171
 
                   const char *digest_path,
172
 
                   apr_pool_t *pool)
 
168
write_digest_file(apr_hash_t *children,
 
169
                  svn_lock_t *lock,
 
170
                  svn_fs_t *fs,
 
171
                  const char *digest_path,
 
172
                  apr_pool_t *pool)
173
173
{
174
174
  svn_error_t *err = SVN_NO_ERROR;
175
175
  apr_file_t *fd;
176
176
  apr_hash_index_t *hi;
177
 
  apr_hash_t *hash = apr_hash_make (pool);
 
177
  apr_hash_t *hash = apr_hash_make(pool);
178
178
  const char *tmp_path;
179
179
 
180
 
  SVN_ERR (ensure_dir_exists (svn_path_join (fs->path, LOCK_ROOT_DIR, pool), 
181
 
                              fs, pool));
182
 
  SVN_ERR (ensure_dir_exists (svn_path_dirname (digest_path, pool), fs, pool));
183
 
  SVN_ERR (svn_io_open_unique_file 
184
 
           (&fd, &tmp_path, digest_path, ".tmp", FALSE, pool));
 
180
  SVN_ERR(ensure_dir_exists(svn_path_join(fs->path, LOCK_ROOT_DIR, pool), 
 
181
                            fs, pool));
 
182
  SVN_ERR(ensure_dir_exists(svn_path_dirname(digest_path, pool), fs, pool));
 
183
  SVN_ERR(svn_io_open_unique_file2
 
184
          (&fd, &tmp_path, digest_path, ".tmp", svn_io_file_del_none, pool));
185
185
 
186
186
  if (lock)
187
187
    {
188
188
      const char *creation_date = NULL, *expiration_date = NULL;
189
189
      if (lock->creation_date)
190
 
        creation_date = svn_time_to_cstring (lock->creation_date, pool);
 
190
        creation_date = svn_time_to_cstring(lock->creation_date, pool);
191
191
      if (lock->expiration_date)
192
 
        expiration_date = svn_time_to_cstring (lock->expiration_date, pool);
193
 
      hash_store (hash, PATH_KEY, sizeof(PATH_KEY)-1,
194
 
                  lock->path, APR_HASH_KEY_STRING, pool); 
195
 
      hash_store (hash, TOKEN_KEY, sizeof(TOKEN_KEY)-1,
196
 
                  lock->token, APR_HASH_KEY_STRING, pool); 
197
 
      hash_store (hash, OWNER_KEY, sizeof(OWNER_KEY)-1,
198
 
                  lock->owner, APR_HASH_KEY_STRING, pool); 
199
 
      hash_store (hash, COMMENT_KEY, sizeof(COMMENT_KEY)-1,
200
 
                  lock->comment, APR_HASH_KEY_STRING, pool); 
201
 
      hash_store (hash, IS_DAV_COMMENT_KEY, sizeof(IS_DAV_COMMENT_KEY)-1,
202
 
                  lock->is_dav_comment ? "1" : "0", 1, pool);
203
 
      hash_store (hash, CREATION_DATE_KEY, sizeof(CREATION_DATE_KEY)-1,
204
 
                  creation_date, APR_HASH_KEY_STRING, pool);
205
 
      hash_store (hash, EXPIRATION_DATE_KEY, sizeof(EXPIRATION_DATE_KEY)-1,
206
 
                  expiration_date, APR_HASH_KEY_STRING, pool);
 
192
        expiration_date = svn_time_to_cstring(lock->expiration_date, pool);
 
193
      hash_store(hash, PATH_KEY, sizeof(PATH_KEY)-1,
 
194
                 lock->path, APR_HASH_KEY_STRING, pool); 
 
195
      hash_store(hash, TOKEN_KEY, sizeof(TOKEN_KEY)-1,
 
196
                 lock->token, APR_HASH_KEY_STRING, pool); 
 
197
      hash_store(hash, OWNER_KEY, sizeof(OWNER_KEY)-1,
 
198
                 lock->owner, APR_HASH_KEY_STRING, pool); 
 
199
      hash_store(hash, COMMENT_KEY, sizeof(COMMENT_KEY)-1,
 
200
                 lock->comment, APR_HASH_KEY_STRING, pool); 
 
201
      hash_store(hash, IS_DAV_COMMENT_KEY, sizeof(IS_DAV_COMMENT_KEY)-1,
 
202
                 lock->is_dav_comment ? "1" : "0", 1, pool);
 
203
      hash_store(hash, CREATION_DATE_KEY, sizeof(CREATION_DATE_KEY)-1,
 
204
                 creation_date, APR_HASH_KEY_STRING, pool);
 
205
      hash_store(hash, EXPIRATION_DATE_KEY, sizeof(EXPIRATION_DATE_KEY)-1,
 
206
                 expiration_date, APR_HASH_KEY_STRING, pool);
207
207
    }
208
 
  if (apr_hash_count (children))
 
208
  if (apr_hash_count(children))
209
209
    {
210
 
      svn_stringbuf_t *children_list = svn_stringbuf_create ("", pool);
 
210
      svn_stringbuf_t *children_list = svn_stringbuf_create("", pool);
211
211
      for (hi = apr_hash_first(pool, children); hi; hi = apr_hash_next(hi)) 
212
212
        {
213
213
          const void *key;
214
214
          apr_ssize_t klen;
215
 
          apr_hash_this (hi, &key, &klen, NULL);
216
 
          svn_stringbuf_appendbytes (children_list, key, klen);
217
 
          svn_stringbuf_appendbytes (children_list, "\n", 1);
 
215
          apr_hash_this(hi, &key, &klen, NULL);
 
216
          svn_stringbuf_appendbytes(children_list, key, klen);
 
217
          svn_stringbuf_appendbytes(children_list, "\n", 1);
218
218
        }
219
 
      hash_store (hash, CHILDREN_KEY, sizeof(CHILDREN_KEY)-1,
220
 
                  children_list->data, children_list->len, pool);
 
219
      hash_store(hash, CHILDREN_KEY, sizeof(CHILDREN_KEY)-1,
 
220
                 children_list->data, children_list->len, pool);
221
221
    } 
222
222
 
223
 
  if ((err = svn_hash_write2 (hash, 
224
 
                              svn_stream_from_aprfile (fd, pool),
225
 
                              SVN_HASH_TERMINATOR, pool)))
 
223
  if ((err = svn_hash_write2(hash, 
 
224
                             svn_stream_from_aprfile(fd, pool),
 
225
                             SVN_HASH_TERMINATOR, pool)))
226
226
    {
227
 
      (void) svn_io_file_close (fd, pool); /* error is relatively unexciting */
228
 
      return svn_error_createf (err->apr_err,
229
 
                                err,
230
 
                                _("Cannot write lock/entries hashfile '%s'"),
231
 
                                svn_path_local_style (tmp_path, pool));
 
227
      svn_error_clear(svn_io_file_close(fd, pool));
 
228
      return svn_error_createf(err->apr_err,
 
229
                               err,
 
230
                               _("Cannot write lock/entries hashfile '%s'"),
 
231
                               svn_path_local_style(tmp_path, pool));
232
232
    }
233
233
 
234
 
  SVN_ERR (svn_io_file_close (fd, pool));
235
 
  SVN_ERR (svn_io_file_rename (tmp_path, digest_path, pool));
236
 
  SVN_ERR (svn_fs_fs__dup_perms 
237
 
           (digest_path, svn_fs_fs__path_rev (fs, 0, pool), pool));
 
234
  SVN_ERR(svn_io_file_close(fd, pool));
 
235
  SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool));
 
236
  SVN_ERR(svn_fs_fs__dup_perms 
 
237
          (digest_path, svn_fs_fs__path_rev(fs, 0, pool), pool));
238
238
 
239
239
  return SVN_NO_ERROR;
240
240
}
245
245
   CHILDREN_P (if any exist, and if *CHILDREN_P is non-NULL).  Use POOL
246
246
   for all allocations.  */
247
247
static svn_error_t *
248
 
read_digest_file (apr_hash_t **children_p,
249
 
                  svn_lock_t **lock_p,
250
 
                  svn_fs_t *fs,
251
 
                  const char *digest_path,
252
 
                  apr_pool_t *pool)
 
248
read_digest_file(apr_hash_t **children_p,
 
249
                 svn_lock_t **lock_p,
 
250
                 svn_fs_t *fs,
 
251
                 const char *digest_path,
 
252
                 apr_pool_t *pool)
253
253
{
254
254
  svn_error_t *err = SVN_NO_ERROR;
255
255
  svn_lock_t *lock;
260
260
  if (lock_p)
261
261
    *lock_p = NULL;
262
262
  if (children_p)
263
 
    *children_p = apr_hash_make (pool);
 
263
    *children_p = apr_hash_make(pool);
264
264
 
265
 
  err = svn_io_file_open (&fd, digest_path, APR_READ, APR_OS_DEFAULT, pool);
266
 
  if (err && APR_STATUS_IS_ENOENT (err->apr_err))
 
265
  err = svn_io_file_open(&fd, digest_path, APR_READ, APR_OS_DEFAULT, pool);
 
266
  if (err && APR_STATUS_IS_ENOENT(err->apr_err))
267
267
    {
268
 
      svn_error_clear (err);
 
268
      svn_error_clear(err);
269
269
      return SVN_NO_ERROR;
270
270
    }
271
 
  SVN_ERR (err);
 
271
  SVN_ERR(err);
272
272
 
273
273
  /* If our caller doesn't care about anything but the presence of the
274
274
     file... whatever. */
275
275
  if (! (lock_p || children_p))
276
 
    return svn_io_file_close (fd, pool);
 
276
    return svn_io_file_close(fd, pool);
277
277
 
278
 
  hash = apr_hash_make (pool);
279
 
  if ((err = svn_hash_read2 (hash, 
280
 
                             svn_stream_from_aprfile (fd, pool),
281
 
                             SVN_HASH_TERMINATOR, pool)))
 
278
  hash = apr_hash_make(pool);
 
279
  if ((err = svn_hash_read2(hash, 
 
280
                            svn_stream_from_aprfile(fd, pool),
 
281
                            SVN_HASH_TERMINATOR, pool)))
282
282
    {
283
 
      (void) svn_io_file_close (fd, pool); /* error is relatively unexciting */
284
 
      return svn_error_createf (err->apr_err,
285
 
                                err,
286
 
                                _("Can't parse lock/entries hashfile '%s'"),
287
 
                                svn_path_local_style (digest_path, pool));
 
283
      svn_error_clear(svn_io_file_close(fd, pool));
 
284
      return svn_error_createf(err->apr_err,
 
285
                               err,
 
286
                               _("Can't parse lock/entries hashfile '%s'"),
 
287
                               svn_path_local_style(digest_path, pool));
288
288
    }
289
 
  SVN_ERR (svn_io_file_close (fd, pool));
 
289
  SVN_ERR(svn_io_file_close(fd, pool));
290
290
 
291
291
  /* If our caller cares, see if we have a lock path in our hash. If
292
292
     so, we'll assume we have a lock here. */
293
 
  val = hash_fetch (hash, PATH_KEY, pool);
 
293
  val = hash_fetch(hash, PATH_KEY, pool);
294
294
  if (val && lock_p)
295
295
    {
296
296
      const char *path = val;
297
297
 
298
298
      /* Create our lock and load it up. */
299
 
      lock = svn_lock_create (pool);
 
299
      lock = svn_lock_create(pool);
300
300
      lock->path = path;
301
301
 
302
 
      if (! ((lock->token = hash_fetch (hash, TOKEN_KEY, pool))))
303
 
        return svn_fs_fs__err_corrupt_lockfile (fs, path);
304
 
 
305
 
      if (! ((lock->owner = hash_fetch (hash, OWNER_KEY, pool))))
306
 
        return svn_fs_fs__err_corrupt_lockfile (fs, path);
307
 
 
308
 
      if (! ((val = hash_fetch (hash, IS_DAV_COMMENT_KEY, pool))))
309
 
        return svn_fs_fs__err_corrupt_lockfile (fs, path);
 
302
      if (! ((lock->token = hash_fetch(hash, TOKEN_KEY, pool))))
 
303
        return svn_fs_fs__err_corrupt_lockfile(fs, path);
 
304
 
 
305
      if (! ((lock->owner = hash_fetch(hash, OWNER_KEY, pool))))
 
306
        return svn_fs_fs__err_corrupt_lockfile(fs, path);
 
307
 
 
308
      if (! ((val = hash_fetch(hash, IS_DAV_COMMENT_KEY, pool))))
 
309
        return svn_fs_fs__err_corrupt_lockfile(fs, path);
310
310
      lock->is_dav_comment = (val[0] == '1') ? TRUE : FALSE;
311
311
 
312
 
      if (! ((val = hash_fetch (hash, CREATION_DATE_KEY, pool))))
313
 
        return svn_fs_fs__err_corrupt_lockfile (fs, path);
314
 
      SVN_ERR (svn_time_from_cstring (&(lock->creation_date), val, pool));
315
 
 
316
 
      if ((val = hash_fetch (hash, EXPIRATION_DATE_KEY, pool)))
317
 
        SVN_ERR (svn_time_from_cstring (&(lock->expiration_date), val, pool));
318
 
 
319
 
      lock->comment = hash_fetch (hash, COMMENT_KEY, pool);
 
312
      if (! ((val = hash_fetch(hash, CREATION_DATE_KEY, pool))))
 
313
        return svn_fs_fs__err_corrupt_lockfile(fs, path);
 
314
      SVN_ERR(svn_time_from_cstring(&(lock->creation_date), val, pool));
 
315
 
 
316
      if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool)))
 
317
        SVN_ERR(svn_time_from_cstring(&(lock->expiration_date), val, pool));
 
318
 
 
319
      lock->comment = hash_fetch(hash, COMMENT_KEY, pool);
320
320
 
321
321
      *lock_p = lock;
322
322
    }
323
323
 
324
324
  /* If our caller cares, see if we have any children for this path. */
325
 
  val = hash_fetch (hash, CHILDREN_KEY, pool);
 
325
  val = hash_fetch(hash, CHILDREN_KEY, pool);
326
326
  if (val && children_p)
327
327
    {
328
 
      apr_array_header_t *kiddos = svn_cstring_split (val, "\n", FALSE, pool);
 
328
      apr_array_header_t *kiddos = svn_cstring_split(val, "\n", FALSE, pool);
329
329
      int i;
330
330
 
331
331
      for (i = 0; i < kiddos->nelts; i++)
332
332
        {
333
 
          apr_hash_set (*children_p, APR_ARRAY_IDX (kiddos, i, const char *),
334
 
                        APR_HASH_KEY_STRING, (void *)1);
 
333
          apr_hash_set(*children_p, APR_ARRAY_IDX(kiddos, i, const char *),
 
334
                       APR_HASH_KEY_STRING, (void *)1);
335
335
        }
336
336
    }
337
337
  return SVN_NO_ERROR;
345
345
 
346
346
/* Write LOCK in FS to the actual OS filesystem. */
347
347
static svn_error_t *
348
 
set_lock (svn_fs_t *fs,
349
 
          svn_lock_t *lock,
350
 
          apr_pool_t *pool)
 
348
set_lock(svn_fs_t *fs,
 
349
         svn_lock_t *lock,
 
350
         apr_pool_t *pool)
351
351
{
352
 
  svn_stringbuf_t *this_path = svn_stringbuf_create (lock->path, pool);
353
 
  svn_stringbuf_t *last_child = svn_stringbuf_create ("", pool);
 
352
  svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
 
353
  svn_stringbuf_t *last_child = svn_stringbuf_create("", pool);
354
354
  apr_pool_t *subpool;
355
355
 
356
 
  assert (lock);
 
356
  assert(lock);
357
357
 
358
358
  /* Iterate in reverse, creating the lock for LOCK->path, and then
359
359
     just adding entries for its parent, until we reach a parent
360
360
     that's already listed in *its* parent. */ 
361
 
  subpool = svn_pool_create (pool);
 
361
  subpool = svn_pool_create(pool);
362
362
  while (1729)
363
363
    {
364
364
      const char *digest_path, *parent_dir, *digest_file;
365
365
      apr_hash_t *this_children;
366
366
      svn_lock_t *this_lock;
367
367
 
368
 
      svn_pool_clear (subpool);
 
368
      svn_pool_clear(subpool);
369
369
 
370
370
      /* Calculate the DIGEST_PATH for the currently FS path, and then
371
371
         split it into a PARENT_DIR and DIGEST_FILE basename. */
372
 
      digest_path = digest_path_from_path (fs, this_path->data, subpool);
373
 
      svn_path_split (digest_path, &parent_dir, &digest_file, subpool);
 
372
      digest_path = digest_path_from_path(fs, this_path->data, subpool);
 
373
      svn_path_split(digest_path, &parent_dir, &digest_file, subpool);
374
374
 
375
 
      SVN_ERR (read_digest_file (&this_children, &this_lock, fs, 
376
 
                                 digest_path, subpool));
 
375
      SVN_ERR(read_digest_file(&this_children, &this_lock, fs, 
 
376
                               digest_path, subpool));
377
377
 
378
378
      /* We're either writing a new lock (first time through only) or
379
379
         a new entry (every time but the first). */
381
381
        {
382
382
          this_lock = lock;
383
383
          lock = NULL;
384
 
          svn_stringbuf_set (last_child, digest_file);
 
384
          svn_stringbuf_set(last_child, digest_file);
385
385
        }
386
386
      else
387
387
        {
388
388
          /* If we already have an entry for this path, we're done. */
389
 
          if (apr_hash_get (this_children, last_child->data, last_child->len))
 
389
          if (apr_hash_get(this_children, last_child->data, last_child->len))
390
390
            break;
391
 
          apr_hash_set (this_children, last_child->data, 
392
 
                        last_child->len, (void *)1);
 
391
          apr_hash_set(this_children, last_child->data, 
 
392
                       last_child->len, (void *)1);
393
393
        }
394
 
      SVN_ERR (write_digest_file (this_children, this_lock, fs, 
395
 
                                  digest_path, subpool));
 
394
      SVN_ERR(write_digest_file(this_children, this_lock, fs, 
 
395
                                digest_path, subpool));
396
396
 
397
397
      /* Prep for next iteration, or bail if we're done. */
398
398
      if ((this_path->len == 1) && (this_path->data[0] == '/'))
399
399
        break;
400
 
      svn_stringbuf_set (this_path, 
401
 
                         svn_path_dirname (this_path->data, subpool));
 
400
      svn_stringbuf_set(this_path, 
 
401
                        svn_path_dirname(this_path->data, subpool));
402
402
    }
403
403
 
404
 
  svn_pool_destroy (subpool);
 
404
  svn_pool_destroy(subpool);
405
405
  return SVN_NO_ERROR;
406
406
}
407
407
 
408
408
/* Delete LOCK from FS in the actual OS filesystem. */
409
409
static svn_error_t *
410
 
delete_lock (svn_fs_t *fs, 
411
 
             svn_lock_t *lock,
412
 
             apr_pool_t *pool)
 
410
delete_lock(svn_fs_t *fs, 
 
411
            svn_lock_t *lock,
 
412
            apr_pool_t *pool)
413
413
{
414
 
  svn_stringbuf_t *this_path = svn_stringbuf_create (lock->path, pool);
415
 
  svn_stringbuf_t *child_to_kill = svn_stringbuf_create ("", pool);
 
414
  svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
 
415
  svn_stringbuf_t *child_to_kill = svn_stringbuf_create("", pool);
416
416
  apr_pool_t *subpool;
417
417
 
418
 
  assert (lock);
 
418
  assert(lock);
419
419
 
420
420
  /* Iterate in reverse, deleting the lock for LOCK->path, and then
421
421
     pruning entries from its parents. */
422
 
  subpool = svn_pool_create (pool);
 
422
  subpool = svn_pool_create(pool);
423
423
  while (1729)
424
424
    {
425
425
      const char *digest_path, *parent_dir, *digest_file;
426
426
      apr_hash_t *this_children;
427
427
      svn_lock_t *this_lock;
428
428
 
429
 
      svn_pool_clear (subpool);
 
429
      svn_pool_clear(subpool);
430
430
 
431
431
      /* Calculate the DIGEST_PATH for the currently FS path, and then
432
432
         split it into a PARENT_DIR and DIGEST_FILE basename. */
433
 
      digest_path = digest_path_from_path (fs, this_path->data, subpool);
434
 
      svn_path_split (digest_path, &parent_dir, &digest_file, subpool);
 
433
      digest_path = digest_path_from_path(fs, this_path->data, subpool);
 
434
      svn_path_split(digest_path, &parent_dir, &digest_file, subpool);
435
435
 
436
 
      SVN_ERR (read_digest_file (&this_children, &this_lock, fs, 
437
 
                                 digest_path, subpool));
 
436
      SVN_ERR(read_digest_file(&this_children, &this_lock, fs, 
 
437
                               digest_path, subpool));
438
438
 
439
439
      /* If we are supposed to drop the last entry from this path's
440
440
         children list, do so. */
441
441
      if (child_to_kill->len)
442
 
        apr_hash_set (this_children, child_to_kill->data, 
443
 
                      child_to_kill->len, NULL);
 
442
        apr_hash_set(this_children, child_to_kill->data, 
 
443
                     child_to_kill->len, NULL);
444
444
        
445
445
      /* Delete the lock (first time through only). */
446
446
      if (lock)
449
449
          lock = NULL;
450
450
        }
451
451
 
452
 
      if (! (this_lock || apr_hash_count (this_children) != 0))
 
452
      if (! (this_lock || apr_hash_count(this_children) != 0))
453
453
        {
454
454
          /* Special case:  no goodz, no file.  And remember to nix
455
455
             the entry for it in its parent. */
456
 
          svn_stringbuf_set (child_to_kill, 
457
 
                             svn_path_basename (digest_path, subpool));
458
 
          SVN_ERR (svn_io_remove_file (digest_path, subpool));
 
456
          svn_stringbuf_set(child_to_kill, 
 
457
                            svn_path_basename(digest_path, subpool));
 
458
          SVN_ERR(svn_io_remove_file(digest_path, subpool));
459
459
        }
460
460
      else
461
461
        {
462
 
          SVN_ERR (write_digest_file (this_children, this_lock, fs, 
463
 
                                      digest_path, subpool));
464
 
          svn_stringbuf_setempty (child_to_kill);
 
462
          SVN_ERR(write_digest_file(this_children, this_lock, fs, 
 
463
                                    digest_path, subpool));
 
464
          svn_stringbuf_setempty(child_to_kill);
465
465
        }
466
466
 
467
467
      /* Prep for next iteration, or bail if we're done. */
468
468
      if ((this_path->len == 1) && (this_path->data[0] == '/'))
469
469
        break;
470
 
      svn_stringbuf_set (this_path, 
471
 
                         svn_path_dirname (this_path->data, subpool));
 
470
      svn_stringbuf_set(this_path, 
 
471
                        svn_path_dirname(this_path->data, subpool));
472
472
    }
473
473
 
474
 
  svn_pool_destroy (subpool);
 
474
  svn_pool_destroy(subpool);
475
475
  return SVN_NO_ERROR;
476
476
}
477
477
 
480
480
   repository-wide write lock, FALSE otherwise.  Use POOL for
481
481
   allocations. */
482
482
static svn_error_t *
483
 
get_lock (svn_lock_t **lock_p,
484
 
          svn_fs_t *fs,
485
 
          const char *path,
486
 
          svn_boolean_t have_write_lock,
487
 
          apr_pool_t *pool)
 
483
get_lock(svn_lock_t **lock_p,
 
484
         svn_fs_t *fs,
 
485
         const char *path,
 
486
         svn_boolean_t have_write_lock,
 
487
         apr_pool_t *pool)
488
488
{
489
489
  svn_lock_t *lock;
490
 
  const char *digest_path = digest_path_from_path (fs, path, pool);
 
490
  const char *digest_path = digest_path_from_path(fs, path, pool);
491
491
 
492
 
  SVN_ERR (read_digest_file (NULL, &lock, fs, digest_path, pool));
 
492
  SVN_ERR(read_digest_file(NULL, &lock, fs, digest_path, pool));
493
493
  if (! lock)
494
 
    return svn_fs_fs__err_no_such_lock (fs, path);
 
494
    return svn_fs_fs__err_no_such_lock(fs, path);
495
495
 
496
496
  /* Don't return an expired lock. */
497
497
  if (lock->expiration_date && (apr_time_now() > lock->expiration_date))
499
499
      /* Only remove the lock if we have the write lock.
500
500
         Read operations shouldn't change the filesystem. */
501
501
      if (have_write_lock)
502
 
        SVN_ERR (delete_lock (fs, lock, pool));
 
502
        SVN_ERR(delete_lock(fs, lock, pool));
503
503
      *lock_p = NULL;
504
 
      return svn_fs_fs__err_lock_expired (fs, lock->token); 
 
504
      return svn_fs_fs__err_lock_expired(fs, lock->token); 
505
505
    }
506
506
  
507
507
  *lock_p = lock;
514
514
   repository-wide write lock, FALSE otherwise.  Use POOL for
515
515
   allocations. */
516
516
static svn_error_t *
517
 
get_lock_helper (svn_fs_t *fs,
518
 
                 svn_lock_t **lock_p,
519
 
                 const char *path,
520
 
                 svn_boolean_t have_write_lock,
521
 
                 apr_pool_t *pool)
 
517
get_lock_helper(svn_fs_t *fs,
 
518
                svn_lock_t **lock_p,
 
519
                const char *path,
 
520
                svn_boolean_t have_write_lock,
 
521
                apr_pool_t *pool)
522
522
{
523
523
  svn_lock_t *lock;
524
524
  svn_error_t *err;
525
525
  
526
 
  err = get_lock (&lock, fs, path, have_write_lock, pool);
 
526
  err = get_lock(&lock, fs, path, have_write_lock, pool);
527
527
 
528
528
  /* We've deliberately decided that this function doesn't tell the
529
529
     caller *why* the lock is unavailable.  */
530
530
  if (err && ((err->apr_err == SVN_ERR_FS_NO_SUCH_LOCK)
531
531
              || (err->apr_err == SVN_ERR_FS_LOCK_EXPIRED)))
532
532
    {
533
 
      svn_error_clear (err);
 
533
      svn_error_clear(err);
534
534
      *lock_p = NULL;
535
535
      return SVN_NO_ERROR;
536
536
    }
537
537
  else
538
 
    SVN_ERR (err);
 
538
    SVN_ERR(err);
539
539
 
540
540
  *lock_p = lock;
541
541
  return SVN_NO_ERROR;
547
547
   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
548
548
   has the FS write lock. */
549
549
static svn_error_t *
550
 
walk_digest_files (svn_fs_t *fs, 
551
 
                   const char *digest_path,
552
 
                   svn_fs_get_locks_callback_t get_locks_func,
553
 
                   void *get_locks_baton,
554
 
                   svn_boolean_t have_write_lock,
555
 
                   apr_pool_t *pool)
 
550
walk_digest_files(svn_fs_t *fs, 
 
551
                  const char *digest_path,
 
552
                  svn_fs_get_locks_callback_t get_locks_func,
 
553
                  void *get_locks_baton,
 
554
                  svn_boolean_t have_write_lock,
 
555
                  apr_pool_t *pool)
556
556
{
557
557
  apr_hash_t *children;
558
558
  svn_lock_t *lock;
560
560
  apr_pool_t *subpool;
561
561
 
562
562
  /* First, send up any locks in the current digest file. */
563
 
  SVN_ERR (read_digest_file (&children, &lock, fs, digest_path, pool));
 
563
  SVN_ERR(read_digest_file(&children, &lock, fs, digest_path, pool));
564
564
  if (lock)
565
565
    {
566
566
      /* Don't report an expired lock. */
568
568
          || (apr_time_now() <= lock->expiration_date))
569
569
        {
570
570
          if (get_locks_func)
571
 
            SVN_ERR (get_locks_func (get_locks_baton, lock, pool));
 
571
            SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
572
572
        }
573
573
      else
574
574
        {
575
575
          /* Only remove the lock if we have the write lock.
576
576
             Read operations shouldn't change the filesystem. */
577
577
          if (have_write_lock)
578
 
            SVN_ERR (delete_lock (fs, lock, pool));
 
578
            SVN_ERR(delete_lock(fs, lock, pool));
579
579
        }
580
580
    }
581
581
 
582
582
  /* Now, recurse on this thing's child entries (if any; bail otherwise). */
583
 
  if (! apr_hash_count (children))
 
583
  if (! apr_hash_count(children))
584
584
    return SVN_NO_ERROR;
585
 
  subpool = svn_pool_create (pool);
 
585
  subpool = svn_pool_create(pool);
586
586
  for (hi = apr_hash_first(pool, children); hi; hi = apr_hash_next(hi)) 
587
587
    {
588
588
      const void *key;
589
 
      svn_pool_clear (subpool);
 
589
      svn_pool_clear(subpool);
590
590
      apr_hash_this(hi, &key, NULL, NULL);
591
 
      SVN_ERR (walk_digest_files 
592
 
               (fs, digest_path_from_digest (fs, key, subpool),
593
 
                get_locks_func, get_locks_baton, have_write_lock, subpool));
 
591
      SVN_ERR(walk_digest_files 
 
592
              (fs, digest_path_from_digest(fs, key, subpool),
 
593
               get_locks_func, get_locks_baton, have_write_lock, subpool));
594
594
    }
595
 
  svn_pool_destroy (subpool);
 
595
  svn_pool_destroy(subpool);
596
596
  return SVN_NO_ERROR;
597
597
}
598
598
 
605
605
      SVN_ERR_FS_BAD_LOCK_TOKEN: FS doesn't hold matching lock-token for LOCK.
606
606
 */
607
607
static svn_error_t *
608
 
verify_lock (svn_fs_t *fs,
609
 
             svn_lock_t *lock,
610
 
             apr_pool_t *pool)
 
608
verify_lock(svn_fs_t *fs,
 
609
            svn_lock_t *lock,
 
610
            apr_pool_t *pool)
611
611
{
612
612
  if ((! fs->access_ctx) || (! fs->access_ctx->username))
613
613
    return svn_error_createf 
615
615
       _("Cannot verify lock on path '%s'; no username available"),
616
616
       lock->path);
617
617
  
618
 
  else if (strcmp (fs->access_ctx->username, lock->owner) != 0)
 
618
  else if (strcmp(fs->access_ctx->username, lock->owner) != 0)
619
619
    return svn_error_createf 
620
620
      (SVN_ERR_FS_LOCK_OWNER_MISMATCH, NULL,
621
621
       _("User %s does not own lock on path '%s' (currently locked by %s)"),
622
622
       fs->access_ctx->username, lock->path, lock->owner);
623
623
 
624
 
  else if (apr_hash_get (fs->access_ctx->lock_tokens, lock->token,
625
 
                         APR_HASH_KEY_STRING) == NULL)
 
624
  else if (apr_hash_get(fs->access_ctx->lock_tokens, lock->token,
 
625
                        APR_HASH_KEY_STRING) == NULL)
626
626
    return svn_error_createf 
627
627
      (SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
628
628
       _("Cannot verify lock on path '%s'; no matching lock-token available"),
635
635
/* This implements the svn_fs_get_locks_callback_t interface, where
636
636
   BATON is just an svn_fs_t object. */
637
637
static svn_error_t *
638
 
get_locks_callback (void *baton, 
639
 
                    svn_lock_t *lock, 
640
 
                    apr_pool_t *pool)
 
638
get_locks_callback(void *baton, 
 
639
                   svn_lock_t *lock, 
 
640
                   apr_pool_t *pool)
641
641
{
642
 
  return verify_lock (baton, lock, pool);
 
642
  return verify_lock(baton, lock, pool);
643
643
}
644
644
 
645
645
 
646
646
/* The main routine for lock enforcement, used throughout libsvn_fs_fs. */
647
647
svn_error_t *
648
 
svn_fs_fs__allow_locked_operation (const char *path,
649
 
                                   svn_fs_t *fs,
650
 
                                   svn_boolean_t recurse,
651
 
                                   svn_boolean_t have_write_lock,
652
 
                                   apr_pool_t *pool)
 
648
svn_fs_fs__allow_locked_operation(const char *path,
 
649
                                  svn_fs_t *fs,
 
650
                                  svn_boolean_t recurse,
 
651
                                  svn_boolean_t have_write_lock,
 
652
                                  apr_pool_t *pool)
653
653
{
654
 
  path = svn_fs_fs__canonicalize_abspath (path, pool);
 
654
  path = svn_fs_fs__canonicalize_abspath(path, pool);
655
655
  if (recurse)
656
656
    {
657
657
      /* Discover all locks at or below the path. */
658
 
      const char *digest_path = digest_path_from_path (fs, path, pool);
659
 
      SVN_ERR (walk_digest_files (fs, digest_path, get_locks_callback,
660
 
                                  fs, have_write_lock, pool));
 
658
      const char *digest_path = digest_path_from_path(fs, path, pool);
 
659
      SVN_ERR(walk_digest_files(fs, digest_path, get_locks_callback,
 
660
                                fs, have_write_lock, pool));
661
661
    }
662
662
  else 
663
663
    {
664
664
      /* Discover and verify any lock attached to the path. */
665
665
      svn_lock_t *lock;
666
 
      SVN_ERR (get_lock_helper (fs, &lock, path, have_write_lock, pool));
 
666
      SVN_ERR(get_lock_helper(fs, &lock, path, have_write_lock, pool));
667
667
      if (lock)
668
 
        SVN_ERR (verify_lock (fs, lock, pool));
 
668
        SVN_ERR(verify_lock(fs, lock, pool));
669
669
    }
670
670
  return SVN_NO_ERROR;
671
671
}
689
689
   type, and assumes that the write lock is held.
690
690
   BATON is a 'struct lock_baton *'. */
691
691
static svn_error_t *
692
 
lock_body (void *baton, apr_pool_t *pool)
 
692
lock_body(void *baton, apr_pool_t *pool)
693
693
{
694
694
  struct lock_baton *lb = baton;
695
695
  svn_node_kind_t kind;
702
702
     on files or non-existent paths. */
703
703
  /* Use fs->vtable->foo instead of svn_fs_foo to avoid circular
704
704
     library dependencies, which are not portable. */
705
 
  SVN_ERR (lb->fs->vtable->youngest_rev (&youngest, lb->fs, pool));
706
 
  SVN_ERR (lb->fs->vtable->revision_root (&root, lb->fs, youngest, pool));
707
 
  SVN_ERR (svn_fs_fs__check_path (&kind, root, lb->path, pool));
 
705
  SVN_ERR(lb->fs->vtable->youngest_rev(&youngest, lb->fs, pool));
 
706
  SVN_ERR(lb->fs->vtable->revision_root(&root, lb->fs, youngest, pool));
 
707
  SVN_ERR(svn_fs_fs__check_path(&kind, root, lb->path, pool));
708
708
  if (kind == svn_node_dir)
709
 
    return svn_fs_fs__err_not_file (lb->fs, lb->path);
 
709
    return svn_fs_fs__err_not_file(lb->fs, lb->path);
710
710
 
711
711
  /* While our locking implementation easily supports the locking of
712
712
     nonexistent paths, we deliberately choose not to allow such madness. */
713
713
  if (kind == svn_node_none)
714
 
    return svn_error_createf (SVN_ERR_FS_NOT_FOUND, NULL,
715
 
                              _("Path '%s' doesn't exist in HEAD revision"),
716
 
                              lb->path);
 
714
    return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
 
715
                             _("Path '%s' doesn't exist in HEAD revision"),
 
716
                             lb->path);
717
717
 
718
718
  /* We need to have a username attached to the fs. */
719
719
  if (!lb->fs->access_ctx || !lb->fs->access_ctx->username)
720
 
    return svn_fs_fs__err_no_user (lb->fs);
 
720
    return svn_fs_fs__err_no_user(lb->fs);
721
721
 
722
722
  /* Is the caller attempting to lock an out-of-date working file? */
723
723
  if (SVN_IS_VALID_REVNUM(lb->current_rev))
724
724
    {
725
725
      svn_revnum_t created_rev;
726
 
      SVN_ERR (svn_fs_fs__node_created_rev (&created_rev, root, lb->path,
727
 
                                            pool));
 
726
      SVN_ERR(svn_fs_fs__node_created_rev(&created_rev, root, lb->path,
 
727
                                          pool));
728
728
 
729
729
      /* SVN_INVALID_REVNUM means the path doesn't exist.  So
730
730
         apparently somebody is trying to lock something in their
757
757
     acceptable to ignore; it means that the path is now free and
758
758
     clear for locking, because the fsfs funcs just cleared out both
759
759
     of the tables for us.   */
760
 
  SVN_ERR (get_lock_helper (lb->fs, &existing_lock, lb->path, TRUE, pool));
 
760
  SVN_ERR(get_lock_helper(lb->fs, &existing_lock, lb->path, TRUE, pool));
761
761
  if (existing_lock)
762
762
    {
763
763
      if (! lb->steal_lock)
764
764
        {
765
765
          /* Sorry, the path is already locked. */
766
 
          return svn_fs_fs__err_path_already_locked (lb->fs, existing_lock);
 
766
          return svn_fs_fs__err_path_already_locked(lb->fs, existing_lock);
767
767
        }
768
768
      else
769
769
        {
770
770
          /* STEAL_LOCK was passed, so fs_username is "stealing" the
771
771
             lock from lock->owner.  Destroy the existing lock. */
772
 
          SVN_ERR (delete_lock (lb->fs, existing_lock, pool));
 
772
          SVN_ERR(delete_lock(lb->fs, existing_lock, pool));
773
773
        }          
774
774
    }
775
775
 
776
776
  /* Create our new lock, and add it to the tables.
777
777
     Ensure that the lock is created in the correct pool. */
778
 
  lock = svn_lock_create (lb->pool);
 
778
  lock = svn_lock_create(lb->pool);
779
779
  if (lb->token)
780
 
    lock->token = apr_pstrdup (lb->pool, lb->token);
 
780
    lock->token = apr_pstrdup(lb->pool, lb->token);
781
781
  else
782
 
    SVN_ERR (svn_fs_fs__generate_lock_token (&(lock->token), lb->fs,
783
 
                                             lb->pool));
784
 
  lock->path = apr_pstrdup (lb->pool, lb->path);
785
 
  lock->owner = apr_pstrdup (lb->pool, lb->fs->access_ctx->username);
786
 
  lock->comment = apr_pstrdup (lb->pool, lb->comment);
 
782
    SVN_ERR(svn_fs_fs__generate_lock_token(&(lock->token), lb->fs,
 
783
                                           lb->pool));
 
784
  lock->path = apr_pstrdup(lb->pool, lb->path);
 
785
  lock->owner = apr_pstrdup(lb->pool, lb->fs->access_ctx->username);
 
786
  lock->comment = apr_pstrdup(lb->pool, lb->comment);
787
787
  lock->is_dav_comment = lb->is_dav_comment;
788
788
  lock->creation_date = apr_time_now();
789
789
  lock->expiration_date = lb->expiration_date;
790
 
  SVN_ERR (set_lock (lb->fs, lock, pool));
 
790
  SVN_ERR(set_lock(lb->fs, lock, pool));
791
791
  *lb->lock_p = lock;
792
792
 
793
793
  return SVN_NO_ERROR;
805
805
   type, and assumes that the write lock is held.
806
806
   BATON is a 'struct unlock_baton *'. */
807
807
static svn_error_t *
808
 
unlock_body (void *baton, apr_pool_t *pool)
 
808
unlock_body(void *baton, apr_pool_t *pool)
809
809
{
810
810
  struct unlock_baton *ub = baton;
811
811
  svn_lock_t *lock;
812
812
 
813
813
  /* This could return SVN_ERR_FS_BAD_LOCK_TOKEN or SVN_ERR_FS_LOCK_EXPIRED. */
814
 
  SVN_ERR (get_lock (&lock, ub->fs, ub->path, TRUE, pool));
 
814
  SVN_ERR(get_lock(&lock, ub->fs, ub->path, TRUE, pool));
815
815
  
816
816
  /* Unless breaking the lock, we do some checks. */
817
817
  if (! ub->break_lock)
818
818
    {
819
819
      /* Sanity check:  the incoming token should match lock->token. */
820
 
      if (strcmp (ub->token, lock->token) != 0)
821
 
        return svn_fs_fs__err_no_such_lock (ub->fs, lock->path);
 
820
      if (strcmp(ub->token, lock->token) != 0)
 
821
        return svn_fs_fs__err_no_such_lock(ub->fs, lock->path);
822
822
 
823
823
      /* There better be a username attached to the fs. */
824
824
      if (! (ub->fs->access_ctx && ub->fs->access_ctx->username))
825
 
        return svn_fs_fs__err_no_user (ub->fs);
 
825
        return svn_fs_fs__err_no_user(ub->fs);
826
826
 
827
827
      /* And that username better be the same as the lock's owner. */
828
 
      if (strcmp (ub->fs->access_ctx->username, lock->owner) != 0)
 
828
      if (strcmp(ub->fs->access_ctx->username, lock->owner) != 0)
829
829
        return svn_fs_fs__err_lock_owner_mismatch
830
830
          (ub->fs, ub->fs->access_ctx->username, lock->owner);
831
831
    }  
832
832
 
833
833
  /* Remove lock and lock token files. */
834
 
  SVN_ERR (delete_lock (ub->fs, lock, pool));
 
834
  SVN_ERR(delete_lock(ub->fs, lock, pool));
835
835
 
836
836
  return SVN_NO_ERROR;
837
837
}
840
840
/*** Public API implementations ***/
841
841
 
842
842
svn_error_t *
843
 
svn_fs_fs__lock (svn_lock_t **lock_p,
844
 
                 svn_fs_t *fs,
845
 
                 const char *path,
846
 
                 const char *token,
847
 
                 const char *comment,
848
 
                 svn_boolean_t is_dav_comment,
849
 
                 apr_time_t expiration_date,
850
 
                 svn_revnum_t current_rev,
851
 
                 svn_boolean_t steal_lock,
852
 
                 apr_pool_t *pool)
 
843
svn_fs_fs__lock(svn_lock_t **lock_p,
 
844
                svn_fs_t *fs,
 
845
                const char *path,
 
846
                const char *token,
 
847
                const char *comment,
 
848
                svn_boolean_t is_dav_comment,
 
849
                apr_time_t expiration_date,
 
850
                svn_revnum_t current_rev,
 
851
                svn_boolean_t steal_lock,
 
852
                apr_pool_t *pool)
853
853
{
854
854
  struct lock_baton lb;
855
855
 
856
 
  SVN_ERR (svn_fs_fs__check_fs (fs));
857
 
  path = svn_fs_fs__canonicalize_abspath (path, pool);
 
856
  SVN_ERR(svn_fs_fs__check_fs(fs));
 
857
  path = svn_fs_fs__canonicalize_abspath(path, pool);
858
858
 
859
859
  lb.lock_p = lock_p;
860
860
  lb.fs = fs;
867
867
  lb.steal_lock = steal_lock;
868
868
  lb.pool = pool;
869
869
 
870
 
  SVN_ERR (svn_fs_fs__with_write_lock (fs, lock_body, &lb, pool));
 
870
  SVN_ERR(svn_fs_fs__with_write_lock(fs, lock_body, &lb, pool));
871
871
 
872
872
  return SVN_NO_ERROR;
873
873
}
874
874
 
875
875
 
876
876
svn_error_t *
877
 
svn_fs_fs__generate_lock_token (const char **token,
878
 
                                svn_fs_t *fs,
879
 
                                apr_pool_t *pool)
 
877
svn_fs_fs__generate_lock_token(const char **token,
 
878
                               svn_fs_t *fs,
 
879
                               apr_pool_t *pool)
880
880
{
881
 
  /* Notice that 'fs' is currently unused.  But perhaps someday,
882
 
     we'll want to use the fs UUID + some incremented number?  */
883
 
  apr_uuid_t uuid;
884
 
  char *uuid_str = apr_pcalloc (pool, APR_UUID_FORMATTED_LENGTH + 1);
885
 
 
886
 
  SVN_ERR (svn_fs_fs__check_fs (fs));
887
 
 
888
 
  apr_uuid_get (&uuid);
889
 
  apr_uuid_format (uuid_str, &uuid);
890
 
 
891
 
  /* For now, we generate a URI that matches the DAV RFC.  We could
892
 
     change this to some other URI scheme someday, if we wish. */
893
 
  *token = apr_pstrcat (pool, "opaquelocktoken:", uuid_str, NULL);
 
881
  SVN_ERR(svn_fs_fs__check_fs(fs));
 
882
 
 
883
  /* Notice that 'fs' is currently unused.  But perhaps someday, we'll
 
884
     want to use the fs UUID + some incremented number?  For now, we
 
885
     generate a URI that matches the DAV RFC.  We could change this to
 
886
     some other URI scheme someday, if we wish. */
 
887
  *token = apr_pstrcat(pool, "opaquelocktoken:", 
 
888
                       svn_uuid_generate(pool), NULL);
894
889
  return SVN_NO_ERROR;
895
890
}
896
891
 
897
892
 
898
893
svn_error_t *
899
 
svn_fs_fs__unlock (svn_fs_t *fs,
900
 
                   const char *path,
901
 
                   const char *token,
902
 
                   svn_boolean_t break_lock,
903
 
                   apr_pool_t *pool)
 
894
svn_fs_fs__unlock(svn_fs_t *fs,
 
895
                  const char *path,
 
896
                  const char *token,
 
897
                  svn_boolean_t break_lock,
 
898
                  apr_pool_t *pool)
904
899
{
905
900
  struct unlock_baton ub;
906
901
 
907
 
  SVN_ERR (svn_fs_fs__check_fs (fs));
908
 
  path = svn_fs_fs__canonicalize_abspath (path, pool);
 
902
  SVN_ERR(svn_fs_fs__check_fs(fs));
 
903
  path = svn_fs_fs__canonicalize_abspath(path, pool);
909
904
 
910
905
  ub.fs = fs;
911
906
  ub.path = path;
912
907
  ub.token = token;
913
908
  ub.break_lock = break_lock;
914
909
 
915
 
  SVN_ERR (svn_fs_fs__with_write_lock (fs, unlock_body, &ub, pool));
 
910
  SVN_ERR(svn_fs_fs__with_write_lock(fs, unlock_body, &ub, pool));
916
911
 
917
912
  return SVN_NO_ERROR;
918
913
}
919
914
 
920
915
 
921
916
svn_error_t *
922
 
svn_fs_fs__get_lock (svn_lock_t **lock_p,
923
 
                     svn_fs_t *fs,
 
917
svn_fs_fs__get_lock(svn_lock_t **lock_p,
 
918
                    svn_fs_t *fs,
 
919
                    const char *path,
 
920
                    apr_pool_t *pool)
 
921
{
 
922
  SVN_ERR(svn_fs_fs__check_fs(fs));
 
923
  path = svn_fs_fs__canonicalize_abspath(path, pool);
 
924
  return get_lock_helper(fs, lock_p, path, FALSE, pool);
 
925
}
 
926
 
 
927
 
 
928
svn_error_t *
 
929
svn_fs_fs__get_locks(svn_fs_t *fs,
924
930
                     const char *path,
 
931
                     svn_fs_get_locks_callback_t get_locks_func,
 
932
                     void *get_locks_baton,
925
933
                     apr_pool_t *pool)
926
934
{
927
 
  SVN_ERR (svn_fs_fs__check_fs (fs));
928
 
  path = svn_fs_fs__canonicalize_abspath (path, pool);
929
 
  return get_lock_helper (fs, lock_p, path, FALSE, pool);
930
 
}
931
 
 
932
 
 
933
 
svn_error_t *
934
 
svn_fs_fs__get_locks (svn_fs_t *fs,
935
 
                      const char *path,
936
 
                      svn_fs_get_locks_callback_t get_locks_func,
937
 
                      void *get_locks_baton,
938
 
                      apr_pool_t *pool)
939
 
{
940
935
  const char *digest_path;
941
936
 
942
 
  SVN_ERR (svn_fs_fs__check_fs (fs));
943
 
  path = svn_fs_fs__canonicalize_abspath (path, pool);
 
937
  SVN_ERR(svn_fs_fs__check_fs(fs));
 
938
  path = svn_fs_fs__canonicalize_abspath(path, pool);
944
939
 
945
940
  /* Get the top digest path in our tree of interest, and then walk it. */
946
 
  digest_path = digest_path_from_path (fs, path, pool);
947
 
  return walk_digest_files (fs, digest_path, get_locks_func, 
948
 
                            get_locks_baton, FALSE, pool);
 
941
  digest_path = digest_path_from_path(fs, path, pool);
 
942
  return walk_digest_files(fs, digest_path, get_locks_func, 
 
943
                           get_locks_baton, FALSE, pool);
949
944
}