📄 version.c
字号:
resource->info->root.txn_name = NULL; resource->info->root.txn = NULL; /* We're no longer checked out. */ resource->info->auto_checked_out = FALSE; /* Convert the working resource back into a regular one, in-place. */ return dav_svn_working_to_regular_resource(resource);}/* Closure object for cleanup_deltify. */struct cleanup_deltify_baton{ /* The repository in which to deltify. We use a path instead of an object, because it's difficult to obtain a repos or fs object with the right lifetime guarantees. */ const char *repos_path; /* The revision number against which to deltify. */ svn_revnum_t revision; /* The pool to use for all temporary allocation while working. This may or may not be the same as the pool on which the cleanup is registered, but obviously it must have a lifetime at least as long as that pool. */ apr_pool_t *pool;};/* APR pool cleanup function to deltify against a just-committed revision. DATA is a 'struct cleanup_deltify_baton *'. If any errors occur, log them in the httpd server error log, but return APR_SUCCESS no matter what, as this is a pool cleanup function and deltification is not a matter of correctness anyway. */static apr_status_t cleanup_deltify(void *data){ struct cleanup_deltify_baton *cdb = data; svn_repos_t *repos; svn_error_t *err; /* It's okay to allocate in the pool that's being cleaned up, and it's also okay to register new cleanups against that pool. But if you create subpools of it, you must make sure to destroy them at the end of the cleanup. So we do all our work in this subpool, then destroy it before exiting. */ apr_pool_t *subpool = svn_pool_create(cdb->pool); err = svn_repos_open(&repos, cdb->repos_path, subpool); if (err) { ap_log_perror(APLOG_MARK, APLOG_ERR, err->apr_err, cdb->pool, "cleanup_deltify: error opening repository '%s'", cdb->repos_path); svn_error_clear(err); goto cleanup; } err = svn_fs_deltify_revision(svn_repos_fs(repos), cdb->revision, subpool); if (err) { ap_log_perror(APLOG_MARK, APLOG_ERR, err->apr_err, cdb->pool, "cleanup_deltify: error deltifying against revision %ld" " in repository '%s'", cdb->revision, cdb->repos_path); svn_error_clear(err); } cleanup: svn_pool_destroy(subpool); return APR_SUCCESS;}/* Register the cleanup_deltify function on POOL, which should be the connection pool for the request. This way the time needed for deltification won't delay the response to the client. REPOS is the repository in which deltify, and REVISION is the revision against which to deltify. POOL is both the pool on which to register the cleanup function and the pool that will be used for temporary allocations while deltifying. */static void register_deltification_cleanup(svn_repos_t *repos, svn_revnum_t revision, apr_pool_t *pool){ struct cleanup_deltify_baton *cdb = apr_palloc(pool, sizeof(*cdb)); cdb->repos_path = svn_repos_path(repos, pool); cdb->revision = revision; cdb->pool = pool; apr_pool_cleanup_register(pool, cdb, cleanup_deltify, apr_pool_cleanup_null);}dav_error *dav_svn_checkin(dav_resource *resource, int keep_checked_out, dav_resource **version_resource){ svn_error_t *serr; dav_error *err; apr_status_t apr_err; const char *uri; const char *shared_activity; void *data; /* ### mod_dav has a flawed architecture, in the sense that it first tries to auto-checkin the modified resource, then attempts to auto-checkin the parent resource (if the parent resource was auto-checked-out). Instead, the provider should be in charge: mod_dav should provide a *set* of resources that need auto-checkin, and the provider can decide how to do it. (One txn? Many txns? Etc.) */ if (resource->type != DAV_RESOURCE_TYPE_WORKING) return dav_svn__new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR, SVN_ERR_UNSUPPORTED_FEATURE, "CHECKIN called on non-working resource.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); /* If the global autoversioning activity still exists, that means nobody's committed it yet. */ apr_err = apr_pool_userdata_get(&data, DAV_SVN_AUTOVERSIONING_ACTIVITY, resource->info->r->pool); if (apr_err) return dav_svn_convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error fetching pool userdata.", resource->pool); shared_activity = data; /* Try to commit the txn if it exists. */ if (shared_activity && (strcmp(shared_activity, resource->info->root.activity_id) == 0)) { const char *shared_txn_name; const char *conflict_msg; svn_revnum_t new_rev; shared_txn_name = dav_svn_get_txn(resource->info->repos, shared_activity); if (! shared_txn_name) return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Cannot look up a txn_name by activity"); /* Sanity checks */ if (resource->info->root.txn_name && (strcmp(shared_txn_name, resource->info->root.txn_name) != 0)) return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Internal txn_name doesn't match" " autoversioning transaction."); if (! resource->info->root.txn) /* should already be open by dav_svn_checkout */ return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Autoversioning txn isn't open " "when it should be."); err = set_auto_revprops(resource); if (err) return err; serr = svn_repos_fs_commit_txn(&conflict_msg, resource->info->repos->repos, &new_rev, resource->info->root.txn, resource->pool); if (serr != NULL) { const char *msg; svn_error_clear(svn_fs_abort_txn(resource->info->root.txn, resource->pool)); if (serr->apr_err == SVN_ERR_FS_CONFLICT) { msg = apr_psprintf(resource->pool, "A conflict occurred during the CHECKIN " "processing. The problem occurred with " "the \"%s\" resource.", conflict_msg); } else msg = "An error occurred while committing the transaction."; /* Attempt to destroy the shared activity. */ dav_svn_delete_activity(resource->info->repos, shared_activity); apr_pool_userdata_set(NULL, DAV_SVN_AUTOVERSIONING_ACTIVITY, NULL, resource->info->r->pool); return dav_svn_convert_err(serr, HTTP_CONFLICT, msg, resource->pool); } /* Attempt to destroy the shared activity. */ dav_svn_delete_activity(resource->info->repos, shared_activity); apr_pool_userdata_set(NULL, DAV_SVN_AUTOVERSIONING_ACTIVITY, NULL, resource->info->r->pool); /* Commit was successful, so schedule deltification. */ register_deltification_cleanup(resource->info->repos->repos, new_rev, resource->info->r->connection->pool); /* If caller wants it, return the new VR that was created by the checkin. */ if (version_resource) { uri = dav_svn_build_uri(resource->info->repos, DAV_SVN_BUILD_URI_VERSION, new_rev, resource->info->repos_path, 0, resource->pool); err = dav_svn_create_version_resource(version_resource, uri, resource->pool); if (err) return err; } } /* end of commit stuff */ /* The shared activity was either nonexistent to begin with, or it's been committed and is only now nonexistent. The resource needs to forget about it. */ resource->info->root.txn_name = NULL; resource->info->root.txn = NULL; /* Convert the working resource back into an regular one. */ if (! keep_checked_out) { resource->info->auto_checked_out = FALSE; return dav_svn_working_to_regular_resource(resource); } return NULL;}static dav_error *dav_svn_avail_reports(const dav_resource *resource, const dav_report_elem **reports){ /* ### further restrict to the public space? */ if (resource->type != DAV_RESOURCE_TYPE_REGULAR) { *reports = NULL; return NULL; } *reports = avail_reports; return NULL;}static int dav_svn_report_label_header_allowed(const apr_xml_doc *doc){ return 0;}/* Respond to a S:dated-rev-report request. The request contains a * DAV:creationdate element giving the requested date; the response * contains a DAV:version-name element giving the most recent revision * as of that date. */static dav_error * dav_svn__drev_report(const dav_resource *resource, const apr_xml_doc *doc, ap_filter_t *output){ apr_xml_elem *child; int ns; apr_time_t tm = (apr_time_t) -1; svn_revnum_t rev; apr_bucket_brigade *bb; svn_error_t *err; apr_status_t apr_err; dav_error *derr = NULL; /* Find the DAV:creationdate element and get the requested time from it. */ ns = dav_svn_find_ns(doc->namespaces, "DAV:"); if (ns != -1) { for (child = doc->root->first_child; child != NULL; child = child->next) { if (child->ns != ns || strcmp(child->name, "creationdate") != 0) continue; /* If this fails, we'll notice below, so ignore any error for now. */ svn_error_clear (svn_time_from_cstring(&tm, dav_xml_get_cdata(child, resource->pool, 1), resource->pool)); } } if (tm == (apr_time_t) -1) { return dav_new_error(resource->pool, HTTP_BAD_REQUEST, 0, "The request does not contain a valid " "'DAV:creationdate' element."); } /* Do the actual work of finding the revision by date. */ if ((err = svn_repos_dated_revision(&rev, resource->info->repos->repos, tm, resource->pool)) != SVN_NO_ERROR) { svn_error_clear(err); return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not access revision times."); } bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); apr_err = ap_fprintf(output, bb, DAV_XML_HEADER DEBUG_CR "<S:dated-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" " "xmlns:D=\"DAV:\">" DEBUG_CR "<D:version-name>%ld</D:version-name>" "</S:dated-rev-report>", rev); if (apr_err) derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error writing REPORT response.", resource->pool); /* Flush the contents of the brigade (returning an error only if we don't already have one). */ if (((apr_err = ap_fflush(output, bb))) && (! derr)) derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error flushing brigade.", resource->pool); return derr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -