Index: subversion/libsvn_wc/lock.c =================================================================== --- subversion/libsvn_wc/lock.c (revision 28380) +++ subversion/libsvn_wc/lock.c (working copy) @@ -24,6 +24,7 @@ #include "svn_pools.h" #include "svn_path.h" #include "svn_sorts.h" +#include "svn_types.h" #include "wc.h" #include "adm_files.h" @@ -1617,3 +1618,62 @@ return FALSE; } + + +/* An implementation of svn_wc_entry_callbacks2_t's found_entry() API. */ +static svn_error_t * +extend_lock_found_entry(const char *path, + const svn_wc_entry_t *entry, + void *walk_baton, + apr_pool_t *pool) +{ + /* If PATH is a directory, and it's not already locked, lock it all + the way down to its leaf nodes. */ + if (entry->kind == svn_node_dir && + strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR) != 0) + { + svn_wc_adm_access_t *anchor_access = walk_baton, *adm_access; + svn_boolean_t write_lock = + (anchor_access->type == svn_wc__adm_access_write_lock); + svn_error_t *err = svn_wc_adm_probe_try3(&adm_access, anchor_access, path, + write_lock, -1, NULL, NULL, pool); + if (err) + { + if (err->apr_err == SVN_ERR_WC_LOCKED) + /* Good! The directory is *already* locked... */ + svn_error_clear(err); + else + return err; + } + } + return SVN_NO_ERROR; +} + + +/* An implementation of svn_wc_entry_callbacks2_t's handle_error() API. */ +static svn_error_t * +extend_lock_handle_error(const char *path, + svn_error_t *err, + void *walk_baton, + apr_pool_t *pool) +{ + return err; +} + + +/* WC entry walker callbacks for svn_wc__adm_extend_lock_to_tree(). */ +static svn_wc_entry_callbacks2_t extend_lock_walker = +{ + extend_lock_found_entry, + extend_lock_handle_error +}; + + +svn_error_t * +svn_wc__adm_extend_lock_to_tree(svn_wc_adm_access_t *adm_access, + apr_pool_t *pool) +{ + return svn_wc_walk_entries3(adm_access->path, adm_access, + &extend_lock_walker, adm_access, + svn_depth_infinity, FALSE, NULL, NULL, pool); +} Index: subversion/libsvn_wc/update_editor.c =================================================================== --- subversion/libsvn_wc/update_editor.c (revision 28380) +++ subversion/libsvn_wc/update_editor.c (working copy) @@ -1110,6 +1110,9 @@ SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->adm_access, parent_path, pool)); + /* Deleting PATH requires that any children it has are also locked + (issue #3039). */ + SVN_ERR(svn_wc__adm_extend_lock_to_tree(eb->adm_access, pool)); SVN_ERR(svn_wc__loggy_delete_entry(&log_item, adm_access, full_path, pool)); Index: subversion/libsvn_wc/lock.h =================================================================== --- subversion/libsvn_wc/lock.h (revision 28380) +++ subversion/libsvn_wc/lock.h (working copy) @@ -119,6 +119,14 @@ */ svn_error_t *svn_wc__adm_write_check(svn_wc_adm_access_t *adm_access); +/* Ensure ADM_ACCESS has a lock and for an entire WC tree (all the way + to its leaf nodes). While locking a tree up front using + LEVELS_TO_LOCK of -1 is a more appropriate operation, this function + can be used to extend the depth of a lock via a tree-crawl after a + lock is taken out. Use POOL for temporary allocations. */ +svn_error_t *svn_wc__adm_extend_lock_to_tree(svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Index: subversion/tests/cmdline/depth_tests.py =================================================================== --- subversion/tests/cmdline/depth_tests.py (revision 28380) +++ subversion/tests/cmdline/depth_tests.py (working copy) @@ -1467,7 +1467,7 @@ add_tree_with_depth_files, upgrade_from_above, status_in_depthy_wc, - XFail(depthy_update_above_dir_to_be_deleted), + depthy_update_above_dir_to_be_deleted, ] if __name__ == "__main__":