📄 update.c
字号:
if (! *cdata) return malformed_element_error(child->name, resource->pool); if (strcmp(cdata, "no") == 0) text_deltas = FALSE; } } /* If the client never sent a <src-path> element, it's old and sending a style of report that we no longer allow. */ if (! src_path) { return dav_svn__new_error_tag (resource->pool, HTTP_BAD_REQUEST, 0, "The request did not contain the '<src-path>' element.\n" "This may indicate that your client is too old.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } /* If a revision for this operation was not dictated to us, this means "update to whatever the current HEAD is now". */ if (revnum == SVN_INVALID_REVNUM) { if ((serr = svn_fs_youngest_rev(&revnum, repos->fs, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not determine the youngest " "revision for the update process.", resource->pool); } uc.svndiff_version = resource->info->svndiff_version; uc.resource = resource; uc.output = output; uc.anchor = src_path; uc.target = target; uc.bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); uc.pathmap = NULL; if (dst_path) /* we're doing a 'switch' */ { if (*target) { /* if the src is split into anchor/target, so must the telescoping dst_path be. */ uc.dst_path = svn_path_dirname(dst_path, resource->pool); /* Also, the svn_repos_dir_delta() is going to preserve our target's name, so we need a pathmap entry for that. */ if (! uc.pathmap) uc.pathmap = apr_hash_make(resource->pool); add_to_path_map(uc.pathmap, svn_path_join(src_path, target, resource->pool), dst_path); } else { uc.dst_path = dst_path; } } else /* we're doing an update, so src and dst are the same. */ uc.dst_path = uc.anchor; /* Get the root of the revision we want to update to. This will be used to generated stable id values. */ if ((serr = svn_fs_revision_root(&uc.rev_root, repos->fs, revnum, resource->pool))) { return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "The revision root could not be created.", resource->pool); } /* If the client did *not* request 'send-all' mode, then we will be sending only a "skelta" of the difference, which will not need to contain actual text deltas. */ if (! uc.send_all) text_deltas = FALSE; /* When we call svn_repos_finish_report, it will ultimately run dir_delta() between REPOS_PATH/TARGET and TARGET_PATH. In the case of an update or status, these paths should be identical. In the case of a switch, they should be different. */ editor = svn_delta_default_editor(resource->pool); editor->set_target_revision = upd_set_target_revision; editor->open_root = upd_open_root; editor->delete_entry = upd_delete_entry; editor->add_directory = upd_add_directory; editor->open_directory = upd_open_directory; editor->change_dir_prop = upd_change_xxx_prop; editor->close_directory = upd_close_directory; editor->absent_directory = upd_absent_directory; editor->add_file = upd_add_file; editor->open_file = upd_open_file; editor->apply_textdelta = upd_apply_textdelta; editor->change_file_prop = upd_change_xxx_prop; editor->close_file = upd_close_file; editor->absent_file = upd_absent_file; editor->close_edit = upd_close_edit; if ((serr = svn_repos_begin_report(&rbaton, revnum, repos->username, repos->repos, src_path, target, dst_path, text_deltas, recurse, ignore_ancestry, editor, &uc, dav_svn_authz_read_func(&arb), &arb, resource->pool))) { return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "The state report gatherer could not be " "created.", resource->pool); } /* scan the XML doc for state information */ for (child = doc->root->first_child; child != NULL; child = child->next) if (child->ns == ns) { /* Clear our subpool. */ svn_pool_clear(subpool); if (strcmp(child->name, "entry") == 0) { const char *path; svn_revnum_t rev = SVN_INVALID_REVNUM; const char *linkpath = NULL; const char *locktoken = NULL; svn_boolean_t start_empty = FALSE; apr_xml_attr *this_attr = child->attr; entry_counter++; while (this_attr) { if (! strcmp(this_attr->name, "rev")) rev = SVN_STR_TO_REV(this_attr->value); else if (! strcmp(this_attr->name, "linkpath")) linkpath = this_attr->value; else if (! strcmp(this_attr->name, "start-empty")) start_empty = entry_is_empty = TRUE; else if (! strcmp(this_attr->name, "lock-token")) locktoken = this_attr->value; this_attr = this_attr->next; } /* we require the `rev' attribute for this to make sense */ if (! SVN_IS_VALID_REVNUM(rev)) { serr = svn_error_create(SVN_ERR_XML_ATTRIB_NOT_FOUND, NULL, "Missing XML attribute: rev"); derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "A failure occurred while " "recording one of the items of " "working copy state.", resource->pool); goto cleanup; } /* get cdata, stripping whitespace */ path = dav_xml_get_cdata(child, subpool, 0); if (! linkpath) serr = svn_repos_set_path2(rbaton, path, rev, start_empty, locktoken, subpool); else serr = svn_repos_link_path2(rbaton, path, linkpath, rev, start_empty, locktoken, subpool); if (serr != NULL) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "A failure occurred while " "recording one of the items of " "working copy state.", resource->pool); goto cleanup; } /* now, add this path to our path map, but only if we are doing a regular update (not a `switch') */ if (linkpath && (! dst_path)) { const char *this_path; if (! uc.pathmap) uc.pathmap = apr_hash_make(resource->pool); this_path = svn_path_join_many(apr_hash_pool_get(uc.pathmap), src_path, target, path, NULL); add_to_path_map(uc.pathmap, this_path, linkpath); } } else if (strcmp(child->name, "missing") == 0) { /* get cdata, stripping whitespace */ const char *path = dav_xml_get_cdata(child, subpool, 0); serr = svn_repos_delete_path(rbaton, path, subpool); if (serr != NULL) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "A failure occurred while " "recording one of the (missing) " "items of working copy state.", resource->pool); goto cleanup; } } } /* Try to deduce what sort of client command is being run,, then make this guess available to apache's logging subsystem. */ { const char *action, *spath; if (target) spath = svn_path_join(src_path, target, resource->pool); else spath = src_path; /* If a second path was passed to svn_repos_dir_delta(), then it must have been switch, diff, or merge. */ if (dst_path) { /* diff/merge don't ask for inline text-deltas. */ if (uc.send_all) action = apr_psprintf(resource->pool, "switch '%s' '%s'", spath, dst_path); else action = apr_psprintf(resource->pool, "diff-or-merge '%s' '%s'", spath, dst_path); } /* Otherwise, it must be checkout, export, or update. */ else { /* svn_client_checkout() creates a single root directory, then reports it (and it alone) to the server as being empty. */ if (entry_counter == 1 && entry_is_empty) action = apr_psprintf(resource->pool, "checkout-or-export '%s'", svn_path_uri_encode(spath, resource->pool)); else { if (text_deltas) action = apr_psprintf(resource->pool, "update '%s'", svn_path_uri_encode(spath, resource->pool)); else action = apr_psprintf(resource->pool, "remote-status '%s'", svn_path_uri_encode(spath, resource->pool)); } } apr_table_set(resource->info->r->subprocess_env, "SVN-ACTION", action); } /* this will complete the report, and then drive our editor to generate the response to the client. */ serr = svn_repos_finish_report(rbaton, resource->pool); if (serr) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "A failure occurred while " "driving the update report editor", resource->pool); goto cleanup; } /* We're finished with the report baton. Note that so we don't try to abort this report later. */ rbaton = NULL; /* ### Temporarily disable resource_walks for single-file switch operations. It isn't strictly necessary. */ if (dst_path && resource_walk) { /* Sanity check: if we switched a file, we can't do a resource walk. dir_delta would choke if we pass a filepath as the 'target'. Also, there's no need to do the walk, since the new vsn-rsc-url was already in the earlier part of the report. */ svn_node_kind_t dst_kind; if ((serr = svn_fs_check_path(&dst_kind, uc.rev_root, dst_path, resource->pool))) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed checking destination path kind.", resource->pool); goto cleanup; } if (dst_kind != svn_node_dir) resource_walk = FALSE; } /* The potential "resource walk" part of the update-report. */ if (dst_path && resource_walk) /* this was a 'switch' operation */ { /* send a second embedded <S:resource-walk> tree that contains the new vsn-rsc-urls for the switched dir. this walk contains essentially nothing but <add> tags. */ svn_fs_root_t *zero_root; serr = svn_fs_revision_root(&zero_root, repos->fs, 0, resource->pool); if (serr) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to find the revision root", resource->pool); goto cleanup; } serr = dav_svn__send_xml(uc.bb, uc.output, "<S:resource-walk>" DEBUG_CR); if (serr) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Unable to begin resource walk", resource->pool); goto cleanup; } uc.resource_walk = TRUE; /* Compare subtree DST_PATH within a pristine revision to revision 0. This should result in nothing but 'add' calls to the editor. */ serr = svn_repos_dir_delta(zero_root, "", target, uc.rev_root, dst_path, /* re-use the editor */ editor, &uc, dav_svn_authz_read_func(&arb), &arb, FALSE /* text-deltas */, recurse, TRUE /* entryprops */, FALSE /* ignore-ancestry */, resource->pool); if (serr) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Resource walk failed.", resource->pool); goto cleanup; } serr = dav_svn__send_xml(uc.bb, uc.output, "</S:resource-walk>" DEBUG_CR); if (serr) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Unable to complete resource walk.", resource->pool); goto cleanup; } } /* Close the report body, unless some error prevented it from being started in the first place. */ if (uc.started_update) { serr = dav_svn__send_xml(uc.bb, uc.output, "</S:update-report>" DEBUG_CR); if (serr) { derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Unable to complete update report.", resource->pool); goto cleanup; } } cleanup: /* Flush the contents of the brigade (returning an error only if we don't already have one). */ if ((! derr) && ((apr_err = ap_fflush(output, uc.bb)))) derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error flushing brigade.", resource->pool); /* if an error was produced EITHER by the dir_delta drive or the resource-walker... */ if (derr) { if (rbaton) svn_error_clear(svn_repos_abort_report(rbaton, resource->pool)); return derr; } /* Destroy our subpool. */ svn_pool_destroy(subpool); return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -