📄 reporter.c
字号:
SVN_ERR(get_source_root(b, &s_root, s_rev)); SVN_ERR(svn_fs_dir_entries(&s_entries, s_root, s_path, pool)); } SVN_ERR(svn_fs_dir_entries(&t_entries, b->t_root, t_path, pool)); /* Iterate over the report information for this directory. */ subpool = svn_pool_create(pool); while (1) { svn_pool_clear(subpool); SVN_ERR(fetch_path_info(b, &name, &info, e_path, subpool)); if (!name) break; if (info && !SVN_IS_VALID_REVNUM(info->rev)) { /* We want to perform deletes before non-replacement adds, for graceful handling of case-only renames on case-insensitive client filesystems. So, if the report item is a delete, remove the entry from the source hash, but don't update the entry yet. */ if (s_entries) apr_hash_set(s_entries, name, APR_HASH_KEY_STRING, NULL); continue; } e_fullpath = svn_path_join(e_path, name, subpool); t_fullpath = svn_path_join(t_path, name, subpool); t_entry = apr_hash_get(t_entries, name, APR_HASH_KEY_STRING); s_fullpath = s_path ? svn_path_join(s_path, name, subpool) : NULL; s_entry = s_entries ? apr_hash_get(s_entries, name, APR_HASH_KEY_STRING) : NULL; SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath, t_entry, dir_baton, e_fullpath, info, b->recurse, subpool)); /* Don't revisit this name in the target or source entries. */ apr_hash_set(t_entries, name, APR_HASH_KEY_STRING, NULL); if (s_entries) apr_hash_set(s_entries, name, APR_HASH_KEY_STRING, NULL); /* pathinfo entries live in their own subpools due to lookahead, so we need to clear each one out as we finish with it. */ if (info) svn_pool_destroy(info->pool); } /* Remove any deleted entries. Do this before processing the target, for graceful handling of case-only renames. */ if (s_entries) { for (hi = apr_hash_first(pool, s_entries); hi; hi = apr_hash_next(hi)) { svn_pool_clear(subpool); apr_hash_this(hi, NULL, NULL, &val); s_entry = val; if (apr_hash_get(t_entries, s_entry->name, APR_HASH_KEY_STRING) == NULL) { /* There is no corresponding target entry, so delete. */ e_fullpath = svn_path_join(e_path, s_entry->name, subpool); if (b->recurse || s_entry->kind != svn_node_dir) SVN_ERR(b->editor->delete_entry(e_fullpath, SVN_INVALID_REVNUM, dir_baton, subpool)); } } } /* Loop over the dirents in the target. */ for (hi = apr_hash_first(pool, t_entries); hi; hi = apr_hash_next(hi)) { svn_pool_clear(subpool); apr_hash_this(hi, NULL, NULL, &val); t_entry = val; /* Compose the report, editor, and target paths for this entry. */ e_fullpath = svn_path_join(e_path, t_entry->name, subpool); t_fullpath = svn_path_join(t_path, t_entry->name, subpool); /* Look for an entry with the same name in the source dirents. */ s_entry = s_entries ? apr_hash_get(s_entries, t_entry->name, APR_HASH_KEY_STRING) : NULL; s_fullpath = s_entry ? svn_path_join(s_path, t_entry->name, subpool) : NULL; SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath, t_entry, dir_baton, e_fullpath, NULL, b->recurse, subpool)); } /* Destroy iteration subpool. */ svn_pool_destroy(subpool); return SVN_NO_ERROR;}static svn_error_t *drive(report_baton_t *b, svn_revnum_t s_rev, path_info_t *info, apr_pool_t *pool){ const char *t_anchor, *s_fullpath; svn_boolean_t allowed, info_is_set_path; svn_fs_root_t *s_root; const svn_fs_dirent_t *s_entry, *t_entry; void *root_baton; /* Compute the target path corresponding to the working copy anchor, and check its authorization. */ t_anchor = *b->s_operand ? svn_path_dirname(b->t_path, pool) : b->t_path; SVN_ERR(check_auth(b, &allowed, t_anchor, pool)); if (!allowed) return svn_error_create (SVN_ERR_AUTHZ_ROOT_UNREADABLE, NULL, _("Not authorized to open root of edit operation")); SVN_ERR(b->editor->set_target_revision(b->edit_baton, b->t_rev, pool)); /* Collect information about the source and target nodes. */ s_fullpath = svn_path_join(b->fs_base, b->s_operand, pool); SVN_ERR(get_source_root(b, &s_root, s_rev)); SVN_ERR(fake_dirent(&s_entry, s_root, s_fullpath, pool)); SVN_ERR(fake_dirent(&t_entry, b->t_root, b->t_path, pool)); /* If the operand is a locally added file or directory, it won't exist in the source, so accept that. */ info_is_set_path = (SVN_IS_VALID_REVNUM(info->rev) && !info->link_path); if (info_is_set_path && !s_entry) s_fullpath = NULL; /* Check if the target path exists first. */ if (!*b->s_operand && !(t_entry)) return svn_error_create(SVN_ERR_FS_PATH_SYNTAX, NULL, _("Target path does not exist")); /* If the anchor is the operand, the source and target must be dirs. Check this before opening the root to avoid modifying the wc. */ else if (!*b->s_operand && (!s_entry || s_entry->kind != svn_node_dir || t_entry->kind != svn_node_dir)) return svn_error_create(SVN_ERR_FS_PATH_SYNTAX, NULL, _("Cannot replace a directory from within")); SVN_ERR(b->editor->open_root(b->edit_baton, s_rev, pool, &root_baton)); /* If the anchor is the operand, diff the two directories; otherwise update the operand within the anchor directory. */ if (!*b->s_operand) SVN_ERR(delta_dirs(b, s_rev, s_fullpath, b->t_path, root_baton, "", info->start_empty, pool)); else SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, b->t_path, t_entry, root_baton, b->s_operand, info, TRUE, pool)); SVN_ERR(b->editor->close_directory(root_baton, pool)); SVN_ERR(b->editor->close_edit(b->edit_baton, pool)); return SVN_NO_ERROR;}/* Initialize the baton fields for editor-driving, and drive the editor. */static svn_error_t *finish_report(report_baton_t *b, apr_pool_t *pool){ apr_off_t offset; path_info_t *info; apr_pool_t *subpool; svn_revnum_t s_rev; int i; /* Save our pool to manage the lookahead and fs_root cache with. */ b->pool = pool; /* Add an end marker and rewind the temporary file. */ SVN_ERR(svn_io_file_write_full(b->tempfile, "-", 1, NULL, pool)); offset = 0; SVN_ERR(svn_io_file_seek(b->tempfile, APR_SET, &offset, pool)); /* Read the first pathinfo from the report and verify that it is a top-level set_path entry. */ SVN_ERR(read_path_info(&info, b->tempfile, pool)); if (!info || strcmp(info->path, b->s_operand) != 0 || info->link_path || !SVN_IS_VALID_REVNUM(info->rev)) return svn_error_create(SVN_ERR_REPOS_BAD_REVISION_REPORT, NULL, _("Invalid report for top level of working copy")); s_rev = info->rev; /* Initialize the lookahead pathinfo. */ subpool = svn_pool_create(pool); SVN_ERR(read_path_info(&b->lookahead, b->tempfile, subpool)); if (b->lookahead && strcmp(b->lookahead->path, b->s_operand) == 0) { /* If the operand of the wc operation is switched or deleted, then info above is just a place-holder, and the only thing we have to do is pass the revision it contains to open_root. The next pathinfo actually describes the target. */ if (!*b->s_operand) return svn_error_create(SVN_ERR_REPOS_BAD_REVISION_REPORT, NULL, _("Two top-level reports with no target")); info = b->lookahead; SVN_ERR(read_path_info(&b->lookahead, b->tempfile, subpool)); } /* Open the target root and initialize the source root cache. */ SVN_ERR(svn_fs_revision_root(&b->t_root, b->repos->fs, b->t_rev, pool)); for (i = 0; i < NUM_CACHED_SOURCE_ROOTS; i++) b->s_roots[i] = NULL; return drive(b, s_rev, info, pool);}/* --- COLLECTING THE REPORT INFORMATION --- *//* Record a report operation into the temporary file. */static svn_error_t *write_path_info(report_baton_t *b, const char *path, const char *lpath, svn_revnum_t rev, svn_boolean_t start_empty, const char *lock_token, apr_pool_t *pool){ const char *lrep, *rrep, *ltrep, *rep; /* Munge the path to be anchor-relative, so that we can use edit paths as report paths. */ path = svn_path_join(b->s_operand, path, pool); lrep = lpath ? apr_psprintf(pool, "+%" APR_SIZE_T_FMT ":%s", strlen(lpath), lpath) : "-"; rrep = (SVN_IS_VALID_REVNUM(rev)) ? apr_psprintf(pool, "+%ld:", rev) : "-"; ltrep = lock_token ? apr_psprintf(pool, "+%" APR_SIZE_T_FMT ":%s", strlen(lock_token), lock_token) : "-"; rep = apr_psprintf(pool, "+%" APR_SIZE_T_FMT ":%s%s%s%c%s", strlen(path), path, lrep, rrep, start_empty ? '+' : '-', ltrep); return svn_io_file_write_full(b->tempfile, rep, strlen(rep), NULL, pool);}svn_error_t *svn_repos_set_path2(void *baton, const char *path, svn_revnum_t rev, svn_boolean_t start_empty, const char *lock_token, apr_pool_t *pool){ return write_path_info(baton, path, NULL, rev, start_empty, lock_token, pool);}svn_error_t *svn_repos_set_path(void *baton, const char *path, svn_revnum_t rev, svn_boolean_t start_empty, apr_pool_t *pool){ return svn_repos_set_path2(baton, path, rev, start_empty, NULL, pool);}svn_error_t *svn_repos_link_path2(void *baton, const char *path, const char *link_path, svn_revnum_t rev, svn_boolean_t start_empty, const char *lock_token, apr_pool_t *pool){ return write_path_info(baton, path, link_path, rev, start_empty, lock_token, pool);}svn_error_t *svn_repos_link_path(void *baton, const char *path, const char *link_path, svn_revnum_t rev, svn_boolean_t start_empty, apr_pool_t *pool){ return svn_repos_link_path2(baton, path, link_path, rev, start_empty, NULL, pool);}svn_error_t *svn_repos_delete_path(void *baton, const char *path, apr_pool_t *pool){ return write_path_info(baton, path, NULL, SVN_INVALID_REVNUM, FALSE, NULL, pool);}svn_error_t *svn_repos_finish_report(void *baton, apr_pool_t *pool){ report_baton_t *b = baton; svn_error_t *finish_err, *close_err; finish_err = finish_report(b, pool); close_err = svn_io_file_close(b->tempfile, pool); if (finish_err) svn_error_clear(close_err); return finish_err ? finish_err : close_err;}svn_error_t *svn_repos_abort_report(void *baton, apr_pool_t *pool){ report_baton_t *b = baton; return svn_io_file_close(b->tempfile, pool);}/* --- BEGINNING THE REPORT --- */svn_error_t *svn_repos_begin_report(void **report_baton, svn_revnum_t revnum, const char *username, svn_repos_t *repos, const char *fs_base, const char *s_operand, const char *switch_path, svn_boolean_t text_deltas, svn_boolean_t recurse, svn_boolean_t ignore_ancestry, const svn_delta_editor_t *editor, void *edit_baton, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, apr_pool_t *pool){ report_baton_t *b; const char *tempdir; /* Build a reporter baton. Copy strings in case the caller doesn't keep track of them. */ b = apr_palloc(pool, sizeof(*b)); b->repos = repos; b->fs_base = apr_pstrdup(pool, fs_base); b->s_operand = apr_pstrdup(pool, s_operand); b->t_rev = revnum; b->t_path = switch_path ? switch_path : svn_path_join(fs_base, s_operand, pool); b->text_deltas = text_deltas; b->recurse = recurse; b->ignore_ancestry = ignore_ancestry; b->is_switch = (switch_path != NULL); b->editor = editor; b->edit_baton = edit_baton; b->authz_read_func = authz_read_func; b->authz_read_baton = authz_read_baton; SVN_ERR(svn_io_temp_dir(&tempdir, pool)); SVN_ERR(svn_io_open_unique_file2(&b->tempfile, NULL, apr_psprintf(pool, "%s/report", tempdir), ".tmp", svn_io_file_del_on_close, pool)); /* Hand reporter back to client. */ *report_baton = b; return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -