static PyObject *fs_get_uuid(PyObject *self) { FileSystemObject *fsobj = (FileSystemObject *)self; const char *uuid; PyObject *ret; apr_pool_t *temp_pool; temp_pool = Pool(NULL); if (temp_pool == NULL) return NULL; RUN_SVN_WITH_POOL(temp_pool, svn_fs_get_uuid(fsobj->fs, &uuid, temp_pool)); ret = PyUnicode_FromString(uuid); apr_pool_destroy(temp_pool); return ret; }
static svn_error_t * svn_ra_local__open(svn_ra_session_t *session, const char *repos_URL, const svn_ra_callbacks2_t *callbacks, void *callback_baton, apr_hash_t *config, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess; const char *fs_path; /* Allocate and stash the session_sess args we have already. */ sess = apr_pcalloc(pool, sizeof(*sess)); sess->callbacks = callbacks; sess->callback_baton = callback_baton; /* Look through the URL, figure out which part points to the repository, and which part is the path *within* the repository. */ SVN_ERR_W(svn_ra_local__split_URL(&(sess->repos), &(sess->repos_url), &fs_path, repos_URL, session->pool), _("Unable to open an ra_local session to URL")); sess->fs_path = svn_stringbuf_create(fs_path, session->pool); /* Cache the filesystem object from the repos here for convenience. */ sess->fs = svn_repos_fs(sess->repos); /* Ignore FS warnings. */ svn_fs_set_warning_func(sess->fs, ignore_warnings, NULL); /* Cache the repository UUID as well */ SVN_ERR(svn_fs_get_uuid(sess->fs, &sess->uuid, session->pool)); /* Be sure username is NULL so we know to look it up / ask for it */ sess->username = NULL; session->priv = sess; return SVN_NO_ERROR; }
static dav_prop_insert insert_prop_internal(const dav_resource *resource, int propid, dav_prop_insert what, apr_text_header *phdr, apr_pool_t *scratch_pool, apr_pool_t *result_pool) { const char *value = NULL; const char *s; const dav_liveprop_spec *info; int global_ns; svn_error_t *serr; /* ** Almost none of the SVN provider properties are defined if the ** resource does not exist. We do need to return the one VCC ** property and baseline-relative-path on lock-null resources, ** however, so that svn clients can run 'svn unlock' and 'svn info' ** on these things. ** ** Even though we state that the SVN properties are not defined, the ** client cannot store dead values -- we deny that thru the is_writable ** hook function. */ if ((! resource->exists) && (propid != DAV_PROPID_version_controlled_configuration) && (propid != SVN_PROPID_baseline_relative_path)) return DAV_PROP_INSERT_NOTSUPP; /* ### we may want to respond to DAV_PROPID_resourcetype for PRIVATE ### resources. need to think on "proper" interaction with mod_dav */ switch (propid) { case DAV_PROPID_getlastmodified: case DAV_PROPID_creationdate: { /* In subversion terms, the date attached to a file's CR is the true "last modified" time. However, we're defining creationdate in the same way. IMO, the "creationdate" is really the date attached to the revision in which the item *first* came into existence; this would found by tracing back through the log of the file -- probably via svn_fs_revisions_changed. gstein, is it a bad thing that we're currently using 'creationdate' to mean the same thing as 'last modified date'? */ const char *datestring; apr_time_t timeval; enum time_format format; /* ### for now, our global VCC has no such property. */ if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && (resource->info->restype == DAV_SVN_RESTYPE_VCC || resource->info->restype == DAV_SVN_RESTYPE_ME)) { return DAV_PROP_INSERT_NOTSUPP; } if (propid == DAV_PROPID_creationdate) { /* Return an ISO8601 date; this is what the svn client expects, and rfc2518 demands it. */ format = time_format_iso8601; } else /* propid == DAV_PROPID_getlastmodified */ { format = time_format_rfc1123; } if (0 != get_last_modified_time(&datestring, &timeval, resource, format, scratch_pool)) { return DAV_PROP_INSERT_NOTDEF; } value = apr_xml_quote_string(scratch_pool, datestring, 1); break; } case DAV_PROPID_creator_displayname: { svn_revnum_t committed_rev = SVN_INVALID_REVNUM; svn_string_t *last_author = NULL; /* ### for now, our global VCC has no such property. */ if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && (resource->info->restype == DAV_SVN_RESTYPE_VCC || resource->info->restype == DAV_SVN_RESTYPE_ME)) { return DAV_PROP_INSERT_NOTSUPP; } if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION) { /* A baseline URI. */ committed_rev = resource->info->root.rev; } else if (resource->type == DAV_RESOURCE_TYPE_REGULAR || resource->type == DAV_RESOURCE_TYPE_WORKING || resource->type == DAV_RESOURCE_TYPE_VERSION) { /* Get the CR field out of the node's skel. Notice that the root object might be an ID root -or- a revision root. */ serr = svn_fs_node_created_rev(&committed_rev, resource->info->root.root, resource->info->repos_path, scratch_pool); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } } else { return DAV_PROP_INSERT_NOTSUPP; } serr = get_path_revprop(&last_author, resource, committed_rev, SVN_PROP_REVISION_AUTHOR, scratch_pool); if (serr) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } if (last_author == NULL) return DAV_PROP_INSERT_NOTDEF; value = apr_xml_quote_string(scratch_pool, last_author->data, 1); break; } case DAV_PROPID_getcontentlanguage: /* ### need something here */ return DAV_PROP_INSERT_NOTSUPP; break; case DAV_PROPID_getcontentlength: { svn_filesize_t len = 0; /* our property, but not defined on collection resources */ if (resource->collection || resource->baselined) return DAV_PROP_INSERT_NOTSUPP; serr = svn_fs_file_length(&len, resource->info->root.root, resource->info->repos_path, scratch_pool); if (serr != NULL) { svn_error_clear(serr); value = "0"; /* ### what to do? */ break; } value = apr_psprintf(scratch_pool, "%" SVN_FILESIZE_T_FMT, len); break; } case DAV_PROPID_getcontenttype: { /* The subversion client assumes that any file without an svn:mime-type property is of type text/plain. So it seems safe (and consistent) to assume the same on the server. */ svn_string_t *pval; const char *mime_type = NULL; if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION) return DAV_PROP_INSERT_NOTSUPP; if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && (resource->info->restype == DAV_SVN_RESTYPE_VCC || resource->info->restype == DAV_SVN_RESTYPE_ME)) { return DAV_PROP_INSERT_NOTSUPP; } if (resource->collection) /* defaults for directories */ { if (resource->info->repos->xslt_uri) mime_type = "text/xml"; else mime_type = "text/html; charset=UTF-8"; } else { if ((serr = svn_fs_node_prop(&pval, resource->info->root.root, resource->info->repos_path, SVN_PROP_MIME_TYPE, scratch_pool))) { svn_error_clear(serr); pval = NULL; } if (pval) mime_type = pval->data; else if ((! resource->info->repos->is_svn_client) && resource->info->r->content_type) mime_type = resource->info->r->content_type; else mime_type = "text/plain"; if ((serr = svn_mime_type_validate(mime_type, scratch_pool))) { /* Probably serr->apr == SVN_ERR_BAD_MIME_TYPE, but there's no point even checking. No matter what the error is, we can't claim to have a mime type for this resource. */ ap_log_rerror(APLOG_MARK, APLOG_WARNING, serr->apr_err, resource->info->r, "%s", serr->message); svn_error_clear(serr); return DAV_PROP_INSERT_NOTDEF; } } value = mime_type; break; } case DAV_PROPID_getetag: if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && (resource->info->restype == DAV_SVN_RESTYPE_VCC || resource->info->restype == DAV_SVN_RESTYPE_ME)) { return DAV_PROP_INSERT_NOTSUPP; } value = dav_svn__getetag(resource, scratch_pool); break; case DAV_PROPID_auto_version: /* we only support one autoversioning behavior, and thus only return this one static value; someday when we support locking, there are other possible values/behaviors for this. */ if (resource->info->repos->autoversioning) value = "DAV:checkout-checkin"; else return DAV_PROP_INSERT_NOTDEF; break; case DAV_PROPID_baseline_collection: /* only defined for Baselines */ /* ### whoops. also defined for a VCC. deal with it later. */ if (resource->type != DAV_RESOURCE_TYPE_VERSION || !resource->baselined) return DAV_PROP_INSERT_NOTSUPP; value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_BC, resource->info->root.rev, NULL, 1 /* add_href */, scratch_pool); break; case DAV_PROPID_checked_in: /* only defined for VCRs (in the public space and in a BC space) */ /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */ if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && (resource->info->restype == DAV_SVN_RESTYPE_VCC || resource->info->restype == DAV_SVN_RESTYPE_ME)) { svn_revnum_t revnum; serr = svn_fs_youngest_rev(&revnum, resource->info->repos->fs, scratch_pool); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } s = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_BASELINE, revnum, NULL, 0 /* add_href */, scratch_pool); value = apr_psprintf(scratch_pool, "<D:href>%s</D:href>", apr_xml_quote_string(scratch_pool, s, 1)); } else if (resource->type != DAV_RESOURCE_TYPE_REGULAR) { /* not defined for this resource type */ return DAV_PROP_INSERT_NOTSUPP; } else { svn_revnum_t rev_to_use = dav_svn__get_safe_cr(resource->info->root.root, resource->info->repos_path, scratch_pool); s = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_VERSION, rev_to_use, resource->info->repos_path, 0 /* add_href */, scratch_pool); value = apr_psprintf(scratch_pool, "<D:href>%s</D:href>", apr_xml_quote_string(scratch_pool, s, 1)); } break; case DAV_PROPID_version_controlled_configuration: /* only defined for VCRs */ /* ### VCRs within the BC should not have this property! */ /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */ if (resource->type != DAV_RESOURCE_TYPE_REGULAR) return DAV_PROP_INSERT_NOTSUPP; value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_VCC, SVN_IGNORED_REVNUM, NULL, 1 /* add_href */, scratch_pool); break; case DAV_PROPID_version_name: /* only defined for Version Resources and Baselines */ /* ### whoops. also defined for VCRs. deal with it later. */ if ((resource->type != DAV_RESOURCE_TYPE_VERSION) && (! resource->versioned)) return DAV_PROP_INSERT_NOTSUPP; if (resource->type == DAV_RESOURCE_TYPE_PRIVATE && (resource->info->restype == DAV_SVN_RESTYPE_VCC || resource->info->restype == DAV_SVN_RESTYPE_ME)) { return DAV_PROP_INSERT_NOTSUPP; } if (resource->baselined) { /* just the revision number for baselines */ value = apr_psprintf(scratch_pool, "%ld", resource->info->root.rev); } else { svn_revnum_t committed_rev = SVN_INVALID_REVNUM; /* Get the CR field out of the node's skel. Notice that the root object might be an ID root -or- a revision root. */ serr = svn_fs_node_created_rev(&committed_rev, resource->info->root.root, resource->info->repos_path, scratch_pool); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } /* Convert the revision into a quoted string */ s = apr_psprintf(scratch_pool, "%ld", committed_rev); value = apr_xml_quote_string(scratch_pool, s, 1); } break; case SVN_PROPID_baseline_relative_path: /* only defined for VCRs */ /* ### VCRs within the BC should not have this property! */ /* ### note that a VCC (a special VCR) is defined as _PRIVATE for now */ if (resource->type != DAV_RESOURCE_TYPE_REGULAR) return DAV_PROP_INSERT_NOTSUPP; /* drop the leading slash, so it is relative */ s = resource->info->repos_path + 1; value = apr_xml_quote_string(scratch_pool, s, 1); break; case SVN_PROPID_md5_checksum: if ((! resource->collection) && (! resource->baselined) && (resource->type == DAV_RESOURCE_TYPE_REGULAR || resource->type == DAV_RESOURCE_TYPE_WORKING || resource->type == DAV_RESOURCE_TYPE_VERSION)) { svn_checksum_t *checksum; serr = svn_fs_file_checksum(&checksum, svn_checksum_md5, resource->info->root.root, resource->info->repos_path, TRUE, scratch_pool); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } value = svn_checksum_to_cstring(checksum, scratch_pool); if (! value) return DAV_PROP_INSERT_NOTSUPP; } else return DAV_PROP_INSERT_NOTSUPP; break; case SVN_PROPID_repository_uuid: serr = svn_fs_get_uuid(resource->info->repos->fs, &value, scratch_pool); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } break; case SVN_PROPID_deadprop_count: { unsigned int propcount; apr_hash_t *proplist; if (resource->type != DAV_RESOURCE_TYPE_REGULAR) return DAV_PROP_INSERT_NOTSUPP; serr = svn_fs_node_proplist(&proplist, resource->info->root.root, resource->info->repos_path, scratch_pool); if (serr != NULL) { /* ### what to do? */ svn_error_clear(serr); value = "###error###"; break; } propcount = apr_hash_count(proplist); value = apr_psprintf(scratch_pool, "%u", propcount); break; } default: /* ### what the heck was this property? */ return DAV_PROP_INSERT_NOTDEF; } /* assert: value != NULL */ /* get the information and global NS index for the property */ global_ns = dav_get_liveprop_info(propid, &dav_svn__liveprop_group, &info); /* assert: info != NULL && info->name != NULL */ if (what == DAV_PROP_INSERT_NAME || (what == DAV_PROP_INSERT_VALUE && *value == '\0')) { s = apr_psprintf(result_pool, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name); } else if (what == DAV_PROP_INSERT_VALUE) { s = apr_psprintf(result_pool, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR, global_ns, info->name, value, global_ns, info->name); } else { /* assert: what == DAV_PROP_INSERT_SUPPORTED */ s = apr_psprintf(result_pool, "<D:supported-live-property D:name=\"%s\" " "D:namespace=\"%s\"/>" DEBUG_CR, info->name, namespace_uris[info->ns]); } apr_text_append(result_pool, phdr, s); /* we inserted whatever was asked for */ return what; }
/* The main dumper. */ svn_error_t * svn_repos_dump_fs3(svn_repos_t *repos, svn_stream_t *stream, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_boolean_t incremental, svn_boolean_t use_deltas, svn_repos_notify_func_t notify_func, void *notify_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { const svn_delta_editor_t *dump_editor; void *dump_edit_baton = NULL; svn_revnum_t i; svn_fs_t *fs = svn_repos_fs(repos); apr_pool_t *subpool = svn_pool_create(pool); svn_revnum_t youngest; const char *uuid; int version; svn_boolean_t found_old_reference = FALSE; svn_boolean_t found_old_mergeinfo = FALSE; svn_repos_notify_t *notify; /* Determine the current youngest revision of the filesystem. */ SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool)); /* Use default vals if necessary. */ if (! SVN_IS_VALID_REVNUM(start_rev)) start_rev = 0; if (! SVN_IS_VALID_REVNUM(end_rev)) end_rev = youngest; if (! stream) stream = svn_stream_empty(pool); /* Validate the revisions. */ if (start_rev > end_rev) return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL, _("Start revision %ld" " is greater than end revision %ld"), start_rev, end_rev); if (end_rev > youngest) return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL, _("End revision %ld is invalid " "(youngest revision is %ld)"), end_rev, youngest); if ((start_rev == 0) && incremental) incremental = FALSE; /* revision 0 looks the same regardless of whether or not this is an incremental dump, so just simplify things. */ /* Write out the UUID. */ SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool)); /* If we're not using deltas, use the previous version, for compatibility with svn 1.0.x. */ version = SVN_REPOS_DUMPFILE_FORMAT_VERSION; if (!use_deltas) version--; /* Write out "general" metadata for the dumpfile. In this case, a magic header followed by a dumpfile format version. */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n", version)); SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid)); /* Create a notify object that we can reuse in the loop. */ if (notify_func) notify = svn_repos_notify_create(svn_repos_notify_dump_rev_end, pool); /* Main loop: we're going to dump revision i. */ for (i = start_rev; i <= end_rev; i++) { svn_revnum_t from_rev, to_rev; svn_fs_root_t *to_root; svn_boolean_t use_deltas_for_rev; svn_pool_clear(subpool); /* Check for cancellation. */ if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); /* Special-case the initial revision dump: it needs to contain *all* nodes, because it's the foundation of all future revisions in the dumpfile. */ if ((i == start_rev) && (! incremental)) { /* Special-special-case a dump of revision 0. */ if (i == 0) { /* Just write out the one revision 0 record and move on. The parser might want to use its properties. */ SVN_ERR(write_revision_record(stream, fs, 0, subpool)); to_rev = 0; goto loop_end; } /* Compare START_REV to revision 0, so that everything appears to be added. */ from_rev = 0; to_rev = i; } else { /* In the normal case, we want to compare consecutive revs. */ from_rev = i - 1; to_rev = i; } /* Write the revision record. */ SVN_ERR(write_revision_record(stream, fs, to_rev, subpool)); /* Fetch the editor which dumps nodes to a file. Regardless of what we've been told, don't use deltas for the first rev of a non-incremental dump. */ use_deltas_for_rev = use_deltas && (incremental || i != start_rev); SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, to_rev, "", stream, notify_func, notify_baton, start_rev, use_deltas_for_rev, FALSE, subpool)); /* Drive the editor in one way or another. */ SVN_ERR(svn_fs_revision_root(&to_root, fs, to_rev, subpool)); /* If this is the first revision of a non-incremental dump, we're in for a full tree dump. Otherwise, we want to simply replay the revision. */ if ((i == start_rev) && (! incremental)) { svn_fs_root_t *from_root; SVN_ERR(svn_fs_revision_root(&from_root, fs, from_rev, subpool)); SVN_ERR(svn_repos_dir_delta2(from_root, "", "", to_root, "", dump_editor, dump_edit_baton, NULL, NULL, FALSE, /* don't send text-deltas */ svn_depth_infinity, FALSE, /* don't send entry props */ FALSE, /* don't ignore ancestry */ subpool)); } else { SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE, dump_editor, dump_edit_baton, NULL, NULL, subpool)); } loop_end: if (notify_func) { notify->revision = to_rev; notify_func(notify_baton, notify, subpool); } if (dump_edit_baton) /* We never get an edit baton for r0. */ { if (((struct edit_baton *)dump_edit_baton)->found_old_reference) found_old_reference = TRUE; if (((struct edit_baton *)dump_edit_baton)->found_old_mergeinfo) found_old_mergeinfo = TRUE; } } if (notify_func) { /* Did we issue any warnings about references to revisions older than the oldest dumped revision? If so, then issue a final generic warning, since the inline warnings already issued might easily be missed. */ notify = svn_repos_notify_create(svn_repos_notify_dump_end, subpool); notify_func(notify_baton, notify, subpool); if (found_old_reference) { notify = svn_repos_notify_create(svn_repos_notify_warning, subpool); notify->warning = svn_repos_notify_warning_found_old_reference; notify->warning_str = _("The range of revisions dumped " "contained references to " "copy sources outside that " "range."); notify_func(notify_baton, notify, subpool); } /* Ditto if we issued any warnings about old revisions referenced in dumped mergeinfo. */ if (found_old_mergeinfo) { notify = svn_repos_notify_create(svn_repos_notify_warning, subpool); notify->warning = svn_repos_notify_warning_found_old_mergeinfo; notify->warning_str = _("The range of revisions dumped " "contained mergeinfo " "which reference revisions outside " "that range."); notify_func(notify_baton, notify, subpool); } } svn_pool_destroy(subpool); return SVN_NO_ERROR; }