📄 adm_ops.c
字号:
{ svn_node_kind_t kind; SVN_ERR(svn_io_check_path(path, &kind, pool)); switch (kind) { case svn_node_none: return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, _("'%s' does not exist"), svn_path_local_style(path, pool)); break; default: /* ### TODO: what do we do here? To handle Unix symlinks we fallthrough to svn_node_file... gulp! */ case svn_node_file: SVN_ERR(svn_io_remove_file(path, pool)); break; case svn_node_dir: /* ### It would be more in the spirit of things to feed the ### cancellation check through to svn_io_remove_dir()... */ if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); SVN_ERR(svn_io_remove_dir(path, pool)); if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); break; } return SVN_NO_ERROR;}/* Remove/erase PATH from the working copy. For files this involves * deletion from the physical filesystem. For directories it involves the * deletion from the filesystem of all unversioned children, and all * versioned children that are files. By the time we get here, added but * not committed items will have been scheduled for deletion which means * they have become unversioned. * * The result is that all that remains are versioned directories, each with * its .svn directory and .svn contents. * * If CANCEL_FUNC is non-null, invoke it with CANCEL_BATON at various * points, return any error immediately. * * KIND is the node kind appropriate for PATH */static svn_error_t *erase_from_wc(const char *path, svn_wc_adm_access_t *adm_access, svn_node_kind_t kind, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool){ /* Check that the item exists in the wc. */ svn_node_kind_t wc_kind; SVN_ERR(svn_io_check_path(path, &wc_kind, pool)); if (wc_kind == svn_node_none) return SVN_NO_ERROR; if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); switch (kind) { default: /* ### TODO: what do we do here? */ break; case svn_node_file: SVN_ERR(svn_io_remove_file(path, pool)); break; case svn_node_dir: { apr_hash_t *ver, *unver; apr_hash_index_t *hi; svn_wc_adm_access_t *dir_access; /* ### Suspect that an iteration or recursion subpool would be good here. */ /* First handle the versioned items, this is better (probably) than simply using svn_io_get_dirents2 for everything as it avoids the need to do svn_io_check_path on each versioned item */ SVN_ERR(svn_wc_adm_retrieve(&dir_access, adm_access, path, pool)); SVN_ERR(svn_wc_entries_read(&ver, dir_access, FALSE, pool)); for (hi = apr_hash_first(pool, ver); hi; hi = apr_hash_next(hi)) { const void *key; void *val; const char *name; const svn_wc_entry_t *entry; const char *down_path; apr_hash_this(hi, &key, NULL, &val); name = key; entry = val; if (!strcmp(name, SVN_WC_ENTRY_THIS_DIR)) continue; down_path = svn_path_join(path, name, pool); SVN_ERR(erase_from_wc(down_path, dir_access, entry->kind, cancel_func, cancel_baton, pool)); } /* Now handle any remaining unversioned items */ SVN_ERR(svn_io_get_dirents2(&unver, path, pool)); for (hi = apr_hash_first(pool, unver); hi; hi = apr_hash_next(hi)) { const void *key; const char *name; const char *down_path; apr_hash_this(hi, &key, NULL, NULL); name = key; /* The admin directory will show up, we don't want to delete it */ if (svn_wc_is_adm_dir(name, pool)) continue; /* Versioned directories will show up, don't delete those either */ if (apr_hash_get(ver, name, APR_HASH_KEY_STRING)) continue; down_path = svn_path_join(path, name, pool); SVN_ERR(erase_unversioned_from_wc (down_path, cancel_func, cancel_baton, pool)); } } /* ### TODO: move this dir into parent's .svn area */ break; } return SVN_NO_ERROR;}svn_error_t *svn_wc_delete2(const char *path, svn_wc_adm_access_t *adm_access, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, void *notify_baton, apr_pool_t *pool){ svn_wc_adm_access_t *dir_access; const svn_wc_entry_t *entry; const char *parent, *base_name; svn_boolean_t was_schedule; svn_node_kind_t was_kind; svn_boolean_t was_copied; svn_boolean_t was_deleted = FALSE; /* Silence a gcc uninitialized warning */ SVN_ERR(svn_wc_adm_probe_try3(&dir_access, adm_access, path, TRUE, -1, cancel_func, cancel_baton, pool)); if (dir_access) SVN_ERR(svn_wc_entry(&entry, path, dir_access, FALSE, pool)); else entry = NULL; if (!entry) return erase_unversioned_from_wc(path, cancel_func, cancel_baton, pool); /* Note: Entries caching? What happens to this entry when the entries file is updated? Lets play safe and copy the values */ was_schedule = entry->schedule; was_kind = entry->kind; was_copied = entry->copied; svn_path_split(path, &parent, &base_name, pool); if (was_kind == svn_node_dir) { svn_wc_adm_access_t *parent_access; apr_hash_t *entries; const svn_wc_entry_t *entry_in_parent; /* The deleted state is only available in the entry in parent's entries file */ SVN_ERR(svn_wc_adm_retrieve(&parent_access, adm_access, parent, pool)); SVN_ERR(svn_wc_entries_read(&entries, parent_access, TRUE, pool)); entry_in_parent = apr_hash_get(entries, base_name, APR_HASH_KEY_STRING); was_deleted = entry_in_parent ? entry_in_parent->deleted : FALSE; if (was_schedule == svn_wc_schedule_add && !was_deleted) { /* Deleting a directory that has been added but not yet committed is easy, just remove the administrative dir. */ if (dir_access != adm_access) { SVN_ERR(svn_wc_remove_from_revision_control (dir_access, SVN_WC_ENTRY_THIS_DIR, FALSE, FALSE, cancel_func, cancel_baton, pool)); } else { /* adm_probe_retrieve returned the parent access baton, which is the same access baton that we came in here with! this means we're dealing with a missing item that's scheduled for addition. Easiest to just remove the entry. */ svn_wc__entry_remove(entries, base_name); SVN_ERR(svn_wc__entries_write(entries, parent_access, pool)); } } else { /* if adm_probe_retrieve returned the parent access baton, (which is the same access baton that we came in here with), this means we're dealing with a missing directory. So there's no tree to mark for deletion. Instead, the next phase of code will simply schedule the directory for deletion in its parent. */ if (dir_access != adm_access) { /* Recursively mark a whole tree for deletion. */ SVN_ERR(mark_tree(dir_access, SVN_WC__ENTRY_MODIFY_SCHEDULE, svn_wc_schedule_delete, FALSE, cancel_func, cancel_baton, notify_func, notify_baton, pool)); } } } if (!(was_kind == svn_node_dir && was_schedule == svn_wc_schedule_add && !was_deleted)) { /* We need to mark this entry for deletion in its parent's entries file, so we split off base_name from the parent path, then fold in the addition of a delete flag. */ svn_stringbuf_t *log_accum = svn_stringbuf_create("", pool); svn_wc_entry_t tmp_entry; /* Edit the entry to reflect the now deleted state. entries.c:fold_entry() clears the values of copied, copyfrom_rev and copyfrom_url. */ tmp_entry.schedule = svn_wc_schedule_delete; SVN_ERR(svn_wc__loggy_entry_modify(&log_accum, adm_access, base_name, &tmp_entry, SVN_WC__ENTRY_MODIFY_SCHEDULE, pool)); /* is it a replacement with history? */ if (was_schedule == svn_wc_schedule_replace && was_copied) { const char *text_base = svn_wc__text_base_path(base_name, FALSE, pool); const char *text_revert = svn_wc__text_revert_path(base_name, FALSE, pool); const char *prop_base, *prop_revert; SVN_ERR(svn_wc__prop_base_path(&prop_base, base_name, was_kind, FALSE, pool)); SVN_ERR(svn_wc__prop_revert_path(&prop_revert, base_name, was_kind, FALSE, pool)); if (was_kind != svn_node_dir) /* Dirs don't have text-bases */ /* Restore the original text-base */ SVN_ERR(svn_wc__loggy_move(&log_accum, NULL, adm_access, text_revert, text_base, FALSE, pool)); SVN_ERR(svn_wc__loggy_move(&log_accum, NULL, adm_access, prop_revert, prop_base, TRUE, pool)); } if (was_schedule == svn_wc_schedule_add) { /* remove the properties file */ const char *svn_prop_file_path; SVN_ERR(svn_wc__prop_path(&svn_prop_file_path, base_name, was_kind, FALSE, pool)); SVN_ERR(svn_wc__loggy_remove(&log_accum, adm_access, svn_prop_file_path, pool)); } SVN_ERR(svn_wc__write_log(adm_access, 0, log_accum, pool)); SVN_ERR(svn_wc__run_log(adm_access, NULL, pool)); } /* Report the deletion to the caller. */ if (notify_func != NULL) (*notify_func)(notify_baton, svn_wc_create_notify(path, svn_wc_notify_delete, pool), pool); /* By the time we get here, anything that was scheduled to be added has become unversioned */ if (was_schedule == svn_wc_schedule_add) SVN_ERR(erase_unversioned_from_wc (path, cancel_func, cancel_baton, pool)); else SVN_ERR(erase_from_wc(path, adm_access, was_kind, cancel_func, cancel_baton, pool)); return SVN_NO_ERROR;}svn_error_t *svn_wc_delete(const char *path, svn_wc_adm_access_t *adm_access, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func_t notify_func, void *notify_baton, apr_pool_t *pool){ svn_wc__compat_notify_baton_t nb; nb.func = notify_func; nb.baton = notify_baton; return svn_wc_delete2(path, adm_access, cancel_func, cancel_baton, svn_wc__compat_call_notify_func, &nb, pool);}svn_error_t *svn_wc_get_ancestry(char **url, svn_revnum_t *rev, const char *path, svn_wc_adm_access_t *adm_access, apr_pool_t *pool){ const svn_wc_entry_t *ent; SVN_ERR(svn_wc_entry(&ent, path, adm_access, FALSE, pool)); if (! ent) return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("'%s' is not under version control"), svn_path_local_style(path, pool)); if (url) *url = apr_pstrdup(pool, ent->url); if (rev) *rev = ent->revision; return SVN_NO_ERROR;}svn_error_t *svn_wc_add2(const char *path, svn_wc_adm_access_t *parent_access, const char *copyfrom_url, svn_revnum_t copyfrom_rev, svn_cancel_func_t cancel_func,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -