📄 commit.c
字号:
extra_headers, 204 /* Created */, 404 /* Not Found */, pool); /* A locking-related error most likely means we were deleting a directory rather than a file, and didn't send all of the necessary lock-tokens within the directory. */ if (serr && ((serr->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN) || (serr->apr_err == SVN_ERR_FS_NO_LOCK_TOKEN) || (serr->apr_err == SVN_ERR_FS_LOCK_OWNER_MISMATCH) || (serr->apr_err == SVN_ERR_FS_PATH_ALREADY_LOCKED))) { /* Re-attempt the DELETE request as if the path were a directory. Discover all lock-tokens within the directory, and send them in the body of the request (which is normally empty). Of course, if we don't *find* any additional lock-tokens, don't bother to retry (it ain't gonna do any good). Note that we're not sending the locks in the If: header, for the same reason we're not sending in MERGE's headers: httpd has limits on the amount of data it's willing to receive in headers. */ apr_hash_t *child_tokens = NULL; ne_request *req; const char *body; const char *token; svn_stringbuf_t *locks_list; if (parent->cc->tokens) child_tokens = get_child_tokens(parent->cc->tokens, path, pool); /* No kiddos? Return the original error. Else, clear it so it doesn't get leaked. */ if ((! child_tokens) || (apr_hash_count(child_tokens) == 0)) return serr; else svn_error_clear(serr); /* In preparation of directory locks, go ahead and add the actual target's lock token to those of its children. */ if ((token = apr_hash_get(parent->cc->tokens, path, APR_HASH_KEY_STRING))) apr_hash_set(child_tokens, path, APR_HASH_KEY_STRING, token); SVN_ERR(svn_ra_dav__assemble_locktoken_body(&locks_list, child_tokens, pool)); req = ne_request_create(parent->cc->ras->sess, "DELETE", child); if (req == NULL) return svn_error_createf(SVN_ERR_RA_DAV_CREATING_REQUEST, NULL, _("Could not create a DELETE request (%s)"), child); body = apr_psprintf(pool, "<?xml version=\"1.0\" encoding=\"utf-8\"?> %s", locks_list->data); ne_set_request_body_buffer(req, body, strlen(body)); /* Don't use SVN_ERR() here because some preprocessors can't handle a compile-time conditional inside a macro call. */ serr = svn_ra_dav__request_dispatch(&code, req, parent->cc->ras->sess, "DELETE", child, 204 /* Created */, 404 /* Not Found */,#ifdef SVN_NEON_0_25 NULL, NULL,#endif /* SVN_NEON_0_25 */ pool); SVN_ERR(serr); } else if (serr) return serr; /* Add this path to the valid targets hash. */ add_valid_target(parent->cc, path, svn_nonrecursive); return SVN_NO_ERROR;}/* A callback of type ne_create_request_fn; called whenever neon creates a request. */static void create_request_hook(ne_request *req, void *userdata, const char *method, const char *requri){ struct copy_baton *cb = userdata; if (strcmp(method, "COPY") == 0) cb->making_a_copy = TRUE;}/* A callback of type ne_pre_send_fn; called whenever neon is just about to send a COPY request. */static voidpre_send_hook(ne_request *req, void *userdata, ne_buffer *header){ struct copy_baton *cb = userdata; if (cb->making_a_copy) { cb->error_parser = ne_xml_create(); svn_ra_dav__add_error_handler(req, cb->error_parser, &(cb->err), cb->pool); }}static svn_error_t * commit_add_dir(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *dir_pool, void **child_baton){ resource_baton_t *parent = parent_baton; resource_baton_t *child; int code; const char *name = svn_path_basename(path, dir_pool); apr_pool_t *workpool = svn_pool_create(dir_pool); version_rsrc_t *rsrc = NULL; /* check out the parent resource so that we can create the new collection as one of its children. */ SVN_ERR(checkout_resource(parent->cc, parent->rsrc, TRUE, NULL, dir_pool)); /* create a child object that contains all the resource urls */ child = apr_pcalloc(dir_pool, sizeof(*child)); child->pool = dir_pool; child->cc = parent->cc; child->created = TRUE; SVN_ERR(add_child(&rsrc, parent->cc, parent->rsrc, name, 1, SVN_INVALID_REVNUM, workpool)); child->rsrc = dup_resource(rsrc, dir_pool); if (! copyfrom_path) { /* This a new directory with no history, so just create a new, empty collection */ SVN_ERR(simple_request(parent->cc->ras, "MKCOL", child->rsrc->wr_url, &code, NULL, 201 /* Created */, 0, workpool)); } else { svn_string_t bc_url, bc_relative; const char *copy_src; int status; /* This add has history, so we need to do a COPY. */ /* Convert the copyfrom_* url/rev "public" pair into a Baseline Collection (BC) URL that represents the revision -- and a relative path under that BC. */ SVN_ERR(svn_ra_dav__get_baseline_info(NULL, &bc_url, &bc_relative, NULL, parent->cc->ras->sess, copyfrom_path, copyfrom_revision, workpool)); /* Combine the BC-URL and relative path; this is the main "source" argument to the COPY request. The "Destination:" header given to COPY is simply the wr_url that is already part of the child object. */ copy_src = svn_path_url_add_component(bc_url.data, bc_relative.data, workpool); /* Have neon do the COPY. */ status = ne_copy(parent->cc->ras->sess, 1, /* overwrite */ NE_DEPTH_INFINITE, /* always copy dirs deeply */ copy_src, /* source URI */ child->rsrc->wr_url); /* dest URI */ /* Did we get a <D:error> response? */ if (parent->cc->cb->err) { if (parent->cc->cb->error_parser) ne_xml_destroy(parent->cc->cb->error_parser); return parent->cc->cb->err; } /* Did we get some error from neon? */ if (status != NE_OK) { const char *msg = apr_psprintf(dir_pool, "COPY of %s", path); if (parent->cc->cb->error_parser) ne_xml_destroy(parent->cc->cb->error_parser); return svn_ra_dav__convert_error(parent->cc->ras->sess, msg, status, workpool); } if (parent->cc->cb->error_parser) ne_xml_destroy(parent->cc->cb->error_parser); } /* Add this path to the valid targets hash. */ add_valid_target(parent->cc, path, copyfrom_path ? svn_recursive : svn_nonrecursive); svn_pool_destroy(workpool); *child_baton = child; return SVN_NO_ERROR;}static svn_error_t * commit_open_dir(const char *path, void *parent_baton, svn_revnum_t base_revision, apr_pool_t *dir_pool, void **child_baton){ resource_baton_t *parent = parent_baton; resource_baton_t *child = apr_pcalloc(dir_pool, sizeof(*child)); const char *name = svn_path_basename(path, dir_pool); apr_pool_t *workpool = svn_pool_create(dir_pool); version_rsrc_t *rsrc = NULL; child->pool = dir_pool; child->cc = parent->cc; child->created = FALSE; SVN_ERR(add_child(&rsrc, parent->cc, parent->rsrc, name, 0, base_revision, workpool)); child->rsrc = dup_resource(rsrc, dir_pool); /* ** Note: open_dir simply means that a change has occurred somewhere ** within this directory. We have nothing to do, to prepare for ** those changes (each will be considered independently). ** ** Note: if a directory is replaced by something else, then this callback ** will not be used: a true replacement is modeled with a "delete" ** followed by an "add". */ svn_pool_destroy(workpool); *child_baton = child; return SVN_NO_ERROR;}static svn_error_t * commit_change_dir_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *pool){ resource_baton_t *dir = dir_baton; /* record the change. it will be applied at close_dir time. */ /* ### we should put this into the dir_baton's pool */ record_prop_change(dir->pool, dir, name, value); /* do the CHECKOUT sooner rather than later */ SVN_ERR(checkout_resource(dir->cc, dir->rsrc, TRUE, NULL, pool)); /* Add this path to the valid targets hash. */ add_valid_target(dir->cc, dir->rsrc->local_path, svn_nonrecursive); return SVN_NO_ERROR;}static svn_error_t * commit_close_dir(void *dir_baton, apr_pool_t *pool){ resource_baton_t *dir = dir_baton; /* Perform all of the property changes on the directory. Note that we checked out the directory when the first prop change was noted. */ SVN_ERR(do_proppatch(dir->cc->ras, dir->rsrc, dir, pool)); return SVN_NO_ERROR;}static svn_error_t * commit_add_file(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *file_pool, void **file_baton){ resource_baton_t *parent = parent_baton; resource_baton_t *file; const char *name = svn_path_basename(path, file_pool); apr_pool_t *workpool = svn_pool_create(file_pool); version_rsrc_t *rsrc = NULL; /* ** To add a new file into the repository, we CHECKOUT the parent ** collection, then PUT the file as a member of the resuling working ** collection. ** ** If the file was copied from elsewhere, then we will use the COPY ** method to copy into the working collection. */ /* Do the parent CHECKOUT first */ SVN_ERR(checkout_resource(parent->cc, parent->rsrc, TRUE, NULL, workpool)); /* Construct a file_baton that contains all the resource urls. */ file = apr_pcalloc(file_pool, sizeof(*file)); file->pool = file_pool; file->cc = parent->cc; file->created = TRUE; SVN_ERR(add_child(&rsrc, parent->cc, parent->rsrc, name, 1, SVN_INVALID_REVNUM, workpool)); file->rsrc = dup_resource(rsrc, file_pool); if (parent->cc->tokens) file->token = apr_hash_get(parent->cc->tokens, path, APR_HASH_KEY_STRING); /* If the parent directory existed before this commit then there may be a file with this URL already. We need to ensure such a file does not exist, which we do by attempting a PROPFIND. Of course, a PROPFIND *should* succeed if this "add" is actually the second half of a "replace". ### For now, we'll assume that if this path has already been added to the valid targets hash, that addition occurred during the "delete" phase (if that's not the case, this editor is being driven incorrectly, as we should never visit the same path twice except in a delete+add situation). */ if ((! parent->created) && (! apr_hash_get(file->cc->valid_targets, path, APR_HASH_KEY_STRING))) { svn_ra_dav_resource_t *res; svn_error_t *err = svn_ra_dav__get_starting_props(&res, file->cc->ras->sess, file->rsrc->url, NULL, workpool); if (!err) { /* If the PROPFIND succeeds the file already exists */ return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL, _("File '%s' already exists"), file->rsrc->url); } else if (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) { svn_error_clear(err); } else { /* A real error */ return err; } } if (! copyfrom_path) { /* This a truly new file. */ /* ### wait for apply_txdelta before doing a PUT. it might arrive a ### "long time" from now. certainly after many other operations, so ### we don't want to start a PUT just yet. ### so... anything else to do here? */ } else { svn_string_t bc_url, bc_relative; const char *copy_src; int status; /* This add has history, so we need to do a COPY. */ /* Convert the copyfrom_* url/rev "public" pair into a Baseline Collection (BC) URL that represents the revision -- and a relative path under that BC. */ SVN_ERR(svn_ra_dav__get_baseline_info(NULL, &bc_url, &bc_relative, NULL, parent->cc->ras->sess, copyfrom_path, copyfrom_revision, workpool)); /* Combine the BC-URL and relative path; this is the main "source" argument to the COPY request. The "Destination:" header given to COPY is simply the wr_url that is already part of the file_baton. */ copy_src = svn_path_url_add_component(bc_url.data, bc_relative.data, workpool); /* Have neon do the COPY. */ status = ne_copy(parent->cc->ras->sess, 1, /* overwrite */ NE_DEPTH_ZERO, /* for a file, does it care? */ copy_src, /* source URI */ file->rsrc->wr_url); /* dest URI */ /* Did we get a <D:error> response? */ if (parent->cc->cb->err) { if (parent->cc->cb->error_parser) ne_xml_destroy(parent->cc->cb->error_parser); return parent->cc->cb->err; } /* Did we get some error from neon? */ if (status != NE_OK) { const char *msg = apr_psprintf(file_pool, "COPY of %s", path); if (parent->cc->cb->error_parser) ne_xml_destroy(parent->cc->cb->error_parser); return svn_ra_dav__convert_error(parent->cc->ras->sess, msg, status, workpool); } if (parent->cc->cb->error_parser)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -