📄 version.c
字号:
TRUE /* tweak in place */); /* Remember that this resource was auto-checked-out, so that dav_svn_auto_versionable allows us to do an auto-checkin and dav_svn_can_be_activity will allow this resource to be an activity. */ resource->info->auto_checked_out = TRUE; /* The txn and txn_root must be open and ready to go in the resource's root object. Normally prep_resource() will do this automatically on a WR's root object. We're converting a VCR to WR forcibly, so it's now our job to make sure it happens. */ derr = open_txn(&resource->info->root.txn, resource->info->repos->fs, resource->info->root.txn_name, resource->pool); if (derr) return derr; serr = svn_fs_txn_root(&resource->info->root.root, resource->info->root.txn, resource->pool); if (serr != NULL) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not open a (transaction) root " "in the repository", resource->pool); return NULL; } /* end of Auto-Versioning Stuff */ if (resource->type != DAV_RESOURCE_TYPE_VERSION) { return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED, SVN_ERR_UNSUPPORTED_FEATURE, "CHECKOUT can only be performed on a " "version resource [at this time].", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } if (create_activity) { return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED, SVN_ERR_UNSUPPORTED_FEATURE, "CHECKOUT can not create an activity at " "this time. Use MKACTIVITY first.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } if (is_unreserved) { return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED, SVN_ERR_UNSUPPORTED_FEATURE, "Unreserved checkouts are not yet " "available. A version history may not be " "checked out more than once, into a " "specific activity.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } if (activities == NULL) { return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, SVN_ERR_INCOMPLETE_DATA, "An activity must be provided for " "checkout.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } /* assert: nelts > 0. the below check effectively means > 1. */ if (activities->nelts != 1) { return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, SVN_ERR_INCORRECT_PARAMS, "Only one activity may be specified within " "the CHECKOUT.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } serr = dav_svn_simple_parse_uri(&parse, resource, APR_ARRAY_IDX(activities, 0, const char *), resource->pool); if (serr != NULL) { /* ### is BAD_REQUEST proper? */ return dav_svn_convert_err(serr, HTTP_CONFLICT, "The activity href could not be parsed " "properly.", resource->pool); } if (parse.activity_id == NULL) { return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, SVN_ERR_INCORRECT_PARAMS, "The provided href is not an activity URI.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } if ((txn_name = dav_svn_get_txn(resource->info->repos, parse.activity_id)) == NULL) { return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, SVN_ERR_APMOD_ACTIVITY_NOT_FOUND, "The specified activity does not exist.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } /* verify the specified version resource is the "latest", thus allowing changes to be made. */ if (resource->baselined || resource->info->root.rev == SVN_INVALID_REVNUM) { /* a Baseline, or a standard Version Resource which was accessed via a Label against a VCR within a Baseline Collection. */ /* ### at the moment, this branch is only reached for baselines */ svn_revnum_t youngest; /* make sure the baseline being checked out is the latest */ serr = svn_fs_youngest_rev(&youngest, resource->info->repos->fs, resource->pool); if (serr != NULL) { /* ### correct HTTP error? */ return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not determine the youngest " "revision for verification against " "the baseline being checked out.", resource->pool); } if (resource->info->root.rev != youngest) { return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, SVN_ERR_APMOD_BAD_BASELINE, "The specified baseline is not the " "latest baseline, so it may not be " "checked out.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); } /* ### hmm. what if the transaction root's revision is different ### from this baseline? i.e. somebody created a new revision while ### we are processing this commit. ### ### first question: what does the client *do* with a working ### baseline? knowing that, and how it maps to our backend, then ### we can figure out what to do here. */ } else { /* standard Version Resource */ svn_fs_txn_t *txn; svn_fs_root_t *txn_root; svn_revnum_t txn_created_rev; dav_error *err; /* open the specified transaction so that we can verify this version resource corresponds to the current/latest in the transaction. */ if ((err = open_txn(&txn, resource->info->repos->fs, txn_name, resource->pool)) != NULL) return err; serr = svn_fs_txn_root(&txn_root, txn, resource->pool); if (serr != NULL) { /* ### correct HTTP error? */ return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not open the transaction tree.", resource->pool); } /* assert: repos_path != NULL (for this type of resource) */ /* Out-of-dateness check: compare the created-rev of the item in the txn against the created-rev of the version resource being changed. */ serr = svn_fs_node_created_rev(&txn_created_rev, txn_root, resource->info->repos_path, resource->pool); if (serr != NULL) { /* ### correct HTTP error? */ return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not get created-rev of " "transaction node.", resource->pool); } /* If txn_created_rev is invalid, that means it's already mutable in the txn... which means it has already passed this out-of-dateness check. (Usually, this happens when looking at a parent directory of an already checked-out resource.) Now, we come down to it. If the created revision of the node in the transaction is different from the revision parsed from the version resource URL, we're in a bit of a quandry, and one of a few things could be true. - The client is trying to modify an old (out of date) revision of the resource. This is, of course, unacceptable! - The client is trying to modify a *newer* revision. If the version resource is *newer* than the transaction root, then the client started a commit, a new revision was created within the repository, the client fetched the new resource from that new revision, changed it (or merged in a prior change), and then attempted to incorporate that into the commit that was initially started. We could copy that new node into our transaction and then modify it, but why bother? We can stop the commit, and everything will be fine again if the user simply restarts it (because we'll use that new revision as the transaction root, thus incorporating the new resource, which they will then modify). - The path/revision that client is wishing to edit and the path/revision in the current transaction are actually the same node, and thus this created-rev comparison didn't really solidify anything after all. :-) */ if (SVN_IS_VALID_REVNUM( txn_created_rev )) { int errorful = 0; if (resource->info->root.rev < txn_created_rev) { /* The item being modified is older than the one in the transaction. The client is out of date. */ errorful = 1; } else if (resource->info->root.rev > txn_created_rev) { /* The item being modified is being accessed via a newer revision than the one in the transaction. We'll check to see if they are still the same node, and if not, return an error. */ const svn_fs_id_t *url_noderev_id, *txn_noderev_id; if ((serr = svn_fs_node_id(&txn_noderev_id, txn_root, resource->info->repos_path, resource->pool))) { err = dav_svn__new_error_tag (resource->pool, HTTP_CONFLICT, serr->apr_err, "Unable to fetch the node revision id of the version " "resource within the transaction.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); svn_error_clear(serr); return err; } if ((serr = svn_fs_node_id(&url_noderev_id, resource->info->root.root, resource->info->repos_path, resource->pool))) { err = dav_svn__new_error_tag (resource->pool, HTTP_CONFLICT, serr->apr_err, "Unable to fetch the node revision id of the version " "resource within the revision.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); svn_error_clear(serr); return err; } if (svn_fs_compare_ids(url_noderev_id, txn_noderev_id) != 0) { errorful = 1; } } if (errorful) {#if 1 return dav_svn__new_error_tag (resource->pool, HTTP_CONFLICT, SVN_ERR_FS_CONFLICT, "The version resource does not correspond to the resource " "within the transaction. Either the requested version " "resource is out of date (needs to be updated), or the " "requested version resource is newer than the transaction " "root (restart the commit).", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);#else /* ### some debugging code */ const char *msg; msg = apr_psprintf(resource->pool, "created-rev mismatch: r=%ld, t=%ld", resource->info->root.rev, txn_created_rev); return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, SVN_ERR_FS_CONFLICT, msg, SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);#endif } } } *working_resource = dav_svn_create_working_resource(resource, parse.activity_id, txn_name, FALSE); return NULL;}static dav_error *dav_svn_uncheckout(dav_resource *resource){ if (resource->type != DAV_RESOURCE_TYPE_WORKING) return dav_svn__new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR, SVN_ERR_UNSUPPORTED_FEATURE, "UNCHECKOUT called on non-working resource.", SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG); /* Try to abort the txn if it exists; but don't try too hard. :-) */ if (resource->info->root.txn) svn_error_clear(svn_fs_abort_txn(resource->info->root.txn, resource->pool)); /* Attempt to destroy the shared activity. */ if (resource->info->root.activity_id) { dav_svn_delete_activity(resource->info->repos, resource->info->root.activity_id); apr_pool_userdata_set(NULL, DAV_SVN_AUTOVERSIONING_ACTIVITY, NULL, resource->info->r->pool); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -