static svn_error_t * svn_ra_local__get_lock(svn_ra_session_t *session, svn_lock_t **lock, const char *path, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); return svn_fs_get_lock(lock, sess->fs, abs_path, pool); }
/* ** Find a particular lock on a resource (specified by its locktoken). ** ** *lock will be set to NULL if the lock is not found. ** ** Note that the provider can optimize the unmarshalling -- only one ** lock (or none) must be constructed and returned. ** ** If partial_ok is true (non-zero), then an indirect lock can be ** partially filled in. Otherwise, another lookup is done and the ** lock structure will be filled out as a DAV_LOCKREC_INDIRECT. */ static dav_error * find_lock(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken *locktoken, int partial_ok, dav_lock **lock) { dav_lockdb_private *info = lockdb->info; svn_error_t *serr; svn_lock_t *slock; dav_lock *dlock = NULL; /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to look up lock by path.", resource->pool); if (slock != NULL) { /* Sanity check. */ if (strcmp(locktoken->uuid_str, slock->token) != 0) return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, DAV_ERR_LOCK_SAVE_LOCK, "Incoming token doesn't match existing " "lock."); svn_lock_to_dav_lock(&dlock, slock, FALSE, resource->exists, resource->pool); /* Let svn clients know the creationdate of the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER, svn_time_to_cstring(slock->creation_date, resource->pool)); /* Let svn clients know the 'owner' of the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER, slock->owner); } *lock = dlock; return 0; }
/* ** Quick test to see if the resource has *any* locks on it. ** ** This is typically used to determine if a non-existent resource ** has a lock and is (therefore) a locknull resource. ** ** WARNING: this function may return TRUE even when timed-out locks ** exist (i.e. it may not perform timeout checks). */ static dav_error * has_locks(dav_lockdb *lockdb, const dav_resource *resource, int *locks_present) { dav_lockdb_private *info = lockdb->info; svn_error_t *serr; svn_lock_t *slock; /* Sanity check: if the resource has no associated path in the fs, then there's nothing to do. */ if (! resource->info->repos_path) { *locks_present = 0; return 0; } /* The Big Lie: if the client ran 'svn lock', then we have to pretend that there's no existing lock. Otherwise mod_dav will throw '403 Locked' without even attempting to create a new lock. For the --force case, this is required and for the non-force case, we allow the filesystem to produce a better error for svn clients. */ if (info->r->method_number == M_LOCK && resource->info->repos->is_svn_client) { *locks_present = 0; return 0; } /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to check path for a lock.", resource->pool); *locks_present = slock ? 1 : 0; return 0; }
/* ** Refresh all locks, found on the specified resource, which has a ** locktoken in the provided list. ** ** If the lock is indirect, then the direct lock is referenced and ** refreshed. ** ** Each lock that is updated is returned in the <locks> argument. ** Note that the locks will be fully resolved. */ static dav_error * refresh_locks(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken_list *ltl, time_t new_time, dav_lock **locks) { /* We're not looping over a list of locks, since we only support one lock per resource. */ dav_locktoken *token = ltl->locktoken; svn_error_t *serr; svn_lock_t *slock; dav_lock *dlock; /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); /* Convert the path into an svn_lock_t. */ serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Token doesn't point to a lock.", resource->pool); /* Sanity check: does the incoming token actually represent the current lock on the incoming resource? */ if ((! slock) || (strcmp(token->uuid_str, slock->token) != 0)) return dav_svn__new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Lock refresh request doesn't match existing " "lock."); /* Now use the tweaked svn_lock_t to 'refresh' the existing lock. */ serr = svn_repos_fs_lock(&slock, resource->info->repos->repos, slock->path, slock->token, slock->comment, slock->is_dav_comment, (new_time == DAV_TIMEOUT_INFINITE) ? 0 : (apr_time_t)new_time * APR_USEC_PER_SEC, SVN_INVALID_REVNUM, TRUE, /* forcibly steal existing lock */ resource->pool); if (serr && serr->apr_err == SVN_ERR_FS_NO_USER) { svn_error_clear(serr); return dav_svn__new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock refreshing is not allowed."); } else if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to refresh existing lock.", resource->pool); /* Convert the refreshed lock into a dav_lock and return it. */ svn_lock_to_dav_lock(&dlock, slock, FALSE, resource->exists, resource->pool); *locks = dlock; return 0; }
/* ** Remove any lock that has the specified locktoken. ** ** If locktoken == NULL, then ALL locks are removed. */ static dav_error * remove_lock(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken *locktoken) { dav_lockdb_private *info = lockdb->info; svn_error_t *serr; svn_lock_t *slock; const char *token = NULL; /* Sanity check: if the resource has no associated path in the fs, then there's nothing to do. */ if (! resource->info->repos_path) return 0; /* Another easy out: if an svn client sent a 'keep_locks' header (typically in a DELETE request, as part of 'svn commit --no-unlock'), then ignore dav_method_delete()'s attempt to unconditionally remove the lock. */ if (info->keep_locks) return 0; /* If the resource's fs path is unreadable, we don't allow a lock to be removed from it. */ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); if (locktoken == NULL) { /* Need to manually discover any lock on the resource. */ serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to check path for a lock.", resource->pool); if (slock) token = slock->token; } else { token = locktoken->uuid_str; } if (token) { /* Notice that a generic DAV client is unable to forcibly 'break' a lock, because info->lock_break will always be FALSE. An svn client, however, can request a 'forced' break.*/ serr = svn_repos_fs_unlock(resource->info->repos->repos, resource->info->repos_path, token, info->lock_break, resource->pool); if (serr && serr->apr_err == SVN_ERR_FS_NO_USER) { svn_error_clear(serr); return dav_svn__new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock removal is not allowed."); } else if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to remove a lock.", resource->pool); /* Log the unlocking as a 'high-level' action. */ dav_svn__operational_log(resource->info, svn_log__unlock_one_path( resource->info->repos_path, info->lock_break, resource->info->r->pool)); } return 0; }
/* ** Get the locks associated with the specified resource. ** ** If resolve_locks is true (non-zero), then any indirect locks are ** resolved to their actual, direct lock (i.e. the reference to followed ** to the original lock). ** ** The locks, if any, are returned as a linked list in no particular ** order. If no locks are present, then *locks will be NULL. ** ** #define DAV_GETLOCKS_RESOLVED 0 -- resolve indirects to directs ** #define DAV_GETLOCKS_PARTIAL 1 -- leave indirects partially filled ** #define DAV_GETLOCKS_COMPLETE 2 -- fill out indirect locks */ static dav_error * get_locks(dav_lockdb *lockdb, const dav_resource *resource, int calltype, dav_lock **locks) { dav_lockdb_private *info = lockdb->info; svn_error_t *serr; svn_lock_t *slock; dav_lock *lock = NULL; /* We only support exclusive locks, not shared ones. So this function always returns a "list" of exactly one lock, or just a NULL list. The 'calltype' arg is also meaningless, since we don't support locks on collections. */ /* Sanity check: if the resource has no associated path in the fs, then there's nothing to do. */ if (! resource->info->repos_path) { *locks = NULL; return 0; } /* The Big Lie: if the client ran 'svn lock', then we have to pretend that there's no existing lock. Otherwise mod_dav will throw '403 Locked' without even attempting to create a new lock. For the --force case, this is required and for the non-force case, we allow the filesystem to produce a better error for svn clients. */ if (info->r->method_number == M_LOCK) { *locks = NULL; return 0; } /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to check path for a lock.", resource->pool); if (slock != NULL) { svn_lock_to_dav_lock(&lock, slock, info->lock_break, resource->exists, resource->pool); /* Let svn clients know the creationdate of the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER, svn_time_to_cstring(slock->creation_date, resource->pool)); /* Let svn clients know who "owns" the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER, slock->owner); } *locks = lock; return 0; }