126
126
PATH, where PATH is the path to the lock file or lock entries file
128
128
static const char *
129
digest_path_from_path (svn_fs_t *fs,
129
digest_path_from_path(svn_fs_t *fs,
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),
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),
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,
143
ensure_dir_exists(const char *path,
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))
150
svn_error_clear (err);
150
svn_error_clear(err);
151
151
return SVN_NO_ERROR;
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));
159
159
return SVN_NO_ERROR;
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,
171
const char *digest_path,
168
write_digest_file(apr_hash_t *children,
171
const char *digest_path,
174
174
svn_error_t *err = SVN_NO_ERROR;
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;
180
SVN_ERR (ensure_dir_exists (svn_path_join (fs->path, LOCK_ROOT_DIR, 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),
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));
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);
208
if (apr_hash_count (children))
208
if (apr_hash_count(children))
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))
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);
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);
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)))
227
(void) svn_io_file_close (fd, pool); /* error is relatively unexciting */
228
return svn_error_createf (err->apr_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,
230
_("Cannot write lock/entries hashfile '%s'"),
231
svn_path_local_style(tmp_path, 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));
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));
239
239
return SVN_NO_ERROR;
263
*children_p = apr_hash_make (pool);
263
*children_p = apr_hash_make(pool);
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))
268
svn_error_clear (err);
268
svn_error_clear(err);
269
269
return SVN_NO_ERROR;
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);
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)))
283
(void) svn_io_file_close (fd, pool); /* error is relatively unexciting */
284
return svn_error_createf (err->apr_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,
286
_("Can't parse lock/entries hashfile '%s'"),
287
svn_path_local_style(digest_path, pool));
289
SVN_ERR (svn_io_file_close (fd, pool));
289
SVN_ERR(svn_io_file_close(fd, pool));
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)
296
296
const char *path = val;
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;
302
if (! ((lock->token = hash_fetch (hash, TOKEN_KEY, pool))))
303
return svn_fs_fs__err_corrupt_lockfile (fs, path);
305
if (! ((lock->owner = hash_fetch (hash, OWNER_KEY, pool))))
306
return svn_fs_fs__err_corrupt_lockfile (fs, path);
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);
305
if (! ((lock->owner = hash_fetch(hash, OWNER_KEY, pool))))
306
return svn_fs_fs__err_corrupt_lockfile(fs, path);
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;
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));
316
if ((val = hash_fetch (hash, EXPIRATION_DATE_KEY, pool)))
317
SVN_ERR (svn_time_from_cstring (&(lock->expiration_date), val, pool));
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));
316
if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool)))
317
SVN_ERR(svn_time_from_cstring(&(lock->expiration_date), val, pool));
319
lock->comment = hash_fetch(hash, COMMENT_KEY, pool);
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)
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);
331
331
for (i = 0; i < kiddos->nelts; i++)
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);
337
337
return SVN_NO_ERROR;
346
346
/* Write LOCK in FS to the actual OS filesystem. */
347
347
static svn_error_t *
348
set_lock (svn_fs_t *fs,
348
set_lock(svn_fs_t *fs,
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;
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);
364
364
const char *digest_path, *parent_dir, *digest_file;
365
365
apr_hash_t *this_children;
366
366
svn_lock_t *this_lock;
368
svn_pool_clear (subpool);
368
svn_pool_clear(subpool);
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);
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));
378
378
/* We're either writing a new lock (first time through only) or
379
379
a new entry (every time but the first). */
382
382
this_lock = lock;
384
svn_stringbuf_set (last_child, digest_file);
384
svn_stringbuf_set(last_child, digest_file);
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))
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);
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));
397
397
/* Prep for next iteration, or bail if we're done. */
398
398
if ((this_path->len == 1) && (this_path->data[0] == '/'))
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));
404
svn_pool_destroy (subpool);
404
svn_pool_destroy(subpool);
405
405
return SVN_NO_ERROR;
408
408
/* Delete LOCK from FS in the actual OS filesystem. */
409
409
static svn_error_t *
410
delete_lock (svn_fs_t *fs,
410
delete_lock(svn_fs_t *fs,
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;
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);
425
425
const char *digest_path, *parent_dir, *digest_file;
426
426
apr_hash_t *this_children;
427
427
svn_lock_t *this_lock;
429
svn_pool_clear (subpool);
429
svn_pool_clear(subpool);
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);
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));
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);
445
445
/* Delete the lock (first time through only). */
452
if (! (this_lock || apr_hash_count (this_children) != 0))
452
if (! (this_lock || apr_hash_count(this_children) != 0))
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));
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);
467
467
/* Prep for next iteration, or bail if we're done. */
468
468
if ((this_path->len == 1) && (this_path->data[0] == '/'))
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));
474
svn_pool_destroy (subpool);
474
svn_pool_destroy(subpool);
475
475
return SVN_NO_ERROR;
568
568
|| (apr_time_now() <= lock->expiration_date))
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));
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));
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))
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));
595
svn_pool_destroy (subpool);
595
svn_pool_destroy(subpool);
596
596
return SVN_NO_ERROR;
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,
638
get_locks_callback(void *baton,
642
return verify_lock (baton, lock, pool);
642
return verify_lock(baton, lock, pool);
646
646
/* The main routine for lock enforcement, used throughout libsvn_fs_fs. */
648
svn_fs_fs__allow_locked_operation (const char *path,
650
svn_boolean_t recurse,
651
svn_boolean_t have_write_lock,
648
svn_fs_fs__allow_locked_operation(const char *path,
650
svn_boolean_t recurse,
651
svn_boolean_t have_write_lock,
654
path = svn_fs_fs__canonicalize_abspath (path, pool);
654
path = svn_fs_fs__canonicalize_abspath(path, pool);
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));
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));
668
SVN_ERR (verify_lock (fs, lock, pool));
668
SVN_ERR(verify_lock(fs, lock, pool));
670
670
return SVN_NO_ERROR;
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);
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"),
714
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
715
_("Path '%s' doesn't exist in HEAD revision"),
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);
722
722
/* Is the caller attempting to lock an out-of-date working file? */
723
723
if (SVN_IS_VALID_REVNUM(lb->current_rev))
725
725
svn_revnum_t created_rev;
726
SVN_ERR (svn_fs_fs__node_created_rev (&created_rev, root, lb->path,
726
SVN_ERR(svn_fs_fs__node_created_rev(&created_rev, root, lb->path,
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)
763
763
if (! lb->steal_lock)
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);
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));
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);
780
lock->token = apr_pstrdup (lb->pool, lb->token);
780
lock->token = apr_pstrdup(lb->pool, lb->token);
782
SVN_ERR (svn_fs_fs__generate_lock_token (&(lock->token), lb->fs,
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,
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;
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)
810
810
struct unlock_baton *ub = baton;
811
811
svn_lock_t *lock;
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));
816
816
/* Unless breaking the lock, we do some checks. */
817
817
if (! ub->break_lock)
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);
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);
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);
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));
836
836
return SVN_NO_ERROR;
867
867
lb.steal_lock = steal_lock;
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));
872
872
return SVN_NO_ERROR;
877
svn_fs_fs__generate_lock_token (const char **token,
877
svn_fs_fs__generate_lock_token(const char **token,
881
/* Notice that 'fs' is currently unused. But perhaps someday,
882
we'll want to use the fs UUID + some incremented number? */
884
char *uuid_str = apr_pcalloc (pool, APR_UUID_FORMATTED_LENGTH + 1);
886
SVN_ERR (svn_fs_fs__check_fs (fs));
888
apr_uuid_get (&uuid);
889
apr_uuid_format (uuid_str, &uuid);
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));
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;
899
svn_fs_fs__unlock (svn_fs_t *fs,
902
svn_boolean_t break_lock,
894
svn_fs_fs__unlock(svn_fs_t *fs,
897
svn_boolean_t break_lock,
905
900
struct unlock_baton ub;
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);
912
907
ub.token = token;
913
908
ub.break_lock = break_lock;
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));
917
912
return SVN_NO_ERROR;
922
svn_fs_fs__get_lock (svn_lock_t **lock_p,
917
svn_fs_fs__get_lock(svn_lock_t **lock_p,
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);
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)
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);
934
svn_fs_fs__get_locks (svn_fs_t *fs,
936
svn_fs_get_locks_callback_t get_locks_func,
937
void *get_locks_baton,
940
935
const char *digest_path;
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);
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);