void svn_cl__print_xml_lock(svn_stringbuf_t **sb, const svn_lock_t *lock, apr_pool_t *pool) { /* "<lock>" */ svn_xml_make_open_tag(sb, pool, svn_xml_normal, "lock", SVN_VA_NULL); /* "<token>xx</token>" */ svn_cl__xml_tagged_cdata(sb, pool, "token", lock->token); /* "<owner>xx</owner>" */ svn_cl__xml_tagged_cdata(sb, pool, "owner", lock->owner); /* "<comment>xx</comment>" */ svn_cl__xml_tagged_cdata(sb, pool, "comment", lock->comment); /* "<created>xx</created>" */ svn_cl__xml_tagged_cdata(sb, pool, "created", svn_time_to_cstring(lock->creation_date, pool)); /* "<expires>xx</expires>" */ if (lock->expiration_date != 0) svn_cl__xml_tagged_cdata(sb, pool, "expires", svn_time_to_cstring(lock->expiration_date, pool)); /* "</lock>" */ svn_xml_make_close_tag(sb, pool, "lock"); }
static svn_error_t * test_time_to_cstring(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { const char *timestring; *msg = "test svn_time_to_cstring"; if (msg_only) return SVN_NO_ERROR; timestring = svn_time_to_cstring(test_timestamp,pool); if (strcmp(timestring,test_timestring) != 0) { return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_time_to_cstring (%" APR_TIME_T_FMT ") returned date string '%s' instead of '%s'", test_timestamp,timestring,test_timestring); } return SVN_NO_ERROR; }
static svn_error_t * test_time_invariant(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { apr_time_t current_timestamp = apr_time_now(); const char *timestring; apr_time_t timestamp; *msg = "test svn_time_[to/from]_cstring() invariant"; if (msg_only) return SVN_NO_ERROR; timestring = svn_time_to_cstring(current_timestamp, pool); SVN_ERR(svn_time_from_cstring(×tamp, timestring, pool)); if (timestamp != current_timestamp) { return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_time_from_cstring ( svn_time_to_cstring (n) ) returned time '%" APR_TIME_T_FMT "' instead of '%" APR_TIME_T_FMT "'", timestamp,current_timestamp); } return SVN_NO_ERROR; }
/* Implements svn_ra_serf__request_body_delegate_t */ static svn_error_t * create_getdate_body(serf_bucket_t **body_bkt, void *baton, serf_bucket_alloc_t *alloc, apr_pool_t *pool /* request pool */, apr_pool_t *scratch_pool) { serf_bucket_t *buckets; date_context_t *date_ctx = baton; buckets = serf_bucket_aggregate_create(alloc); svn_ra_serf__add_open_tag_buckets(buckets, alloc, "S:dated-rev-report", "xmlns:S", SVN_XML_NAMESPACE, "xmlns:D", "DAV:", SVN_VA_NULL); svn_ra_serf__add_tag_buckets(buckets, "D:" SVN_DAV__CREATIONDATE, svn_time_to_cstring(date_ctx->time, pool), alloc); svn_ra_serf__add_close_tag_buckets(buckets, alloc, "S:dated-rev-report"); *body_bkt = buckets; return SVN_NO_ERROR; }
const char * svn_opt__revision_to_string(const svn_opt_revision_t *revision, apr_pool_t *result_pool) { switch (revision->kind) { case svn_opt_revision_unspecified: return "unspecified"; case svn_opt_revision_number: return apr_psprintf(result_pool, "%ld", revision->value.number); case svn_opt_revision_date: /* ### svn_time_to_human_cstring()? */ return svn_time_to_cstring(revision->value.date, result_pool); case svn_opt_revision_committed: return "committed"; case svn_opt_revision_previous: return "previous"; case svn_opt_revision_base: return "base"; case svn_opt_revision_working: return "working"; case svn_opt_revision_head: return "head"; default: return NULL; } }
/* Helper for svn_repos_dump_fs. Write a revision record of REV in FS to writable STREAM, using POOL. */ static svn_error_t * write_revision_record(svn_stream_t *stream, svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) { apr_size_t len; apr_hash_t *props; svn_stringbuf_t *encoded_prophash; apr_time_t timetemp; svn_string_t *datevalue; svn_stream_t *propstream; /* Read the revision props even if we're aren't going to dump them for verification purposes */ SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool)); /* Run revision date properties through the time conversion to canonicalize them. */ /* ### Remove this when it is no longer needed for sure. */ datevalue = apr_hash_get(props, SVN_PROP_REVISION_DATE, APR_HASH_KEY_STRING); if (datevalue) { SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool)); datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool), pool); apr_hash_set(props, SVN_PROP_REVISION_DATE, APR_HASH_KEY_STRING, datevalue); } encoded_prophash = svn_stringbuf_create_ensure(0, pool); propstream = svn_stream_from_stringbuf(encoded_prophash, pool); SVN_ERR(svn_hash_write2(props, propstream, "PROPS-END", pool)); SVN_ERR(svn_stream_close(propstream)); /* ### someday write a revision-content-checksum */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n", rev)); SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n", encoded_prophash->len)); /* Write out a regular Content-length header for the benefit of non-Subversion RFC-822 parsers. */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n\n", encoded_prophash->len)); len = encoded_prophash->len; SVN_ERR(svn_stream_write(stream, encoded_prophash->data, &len)); len = 1; return svn_stream_write(stream, "\n", &len); }
/* ** Find a particular lock on a resource (specified by its locktoken). ** ** *lock will be set to NULL if the lock is not found. ** ** Note that the provider can optimize the unmarshalling -- only one ** lock (or none) must be constructed and returned. ** ** If partial_ok is true (non-zero), then an indirect lock can be ** partially filled in. Otherwise, another lookup is done and the ** lock structure will be filled out as a DAV_LOCKREC_INDIRECT. */ static dav_error * find_lock(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken *locktoken, int partial_ok, dav_lock **lock) { dav_lockdb_private *info = lockdb->info; svn_error_t *serr; svn_lock_t *slock; dav_lock *dlock = NULL; /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to look up lock by path.", resource->pool); if (slock != NULL) { /* Sanity check. */ if (strcmp(locktoken->uuid_str, slock->token) != 0) return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, DAV_ERR_LOCK_SAVE_LOCK, "Incoming token doesn't match existing " "lock."); svn_lock_to_dav_lock(&dlock, slock, FALSE, resource->exists, resource->pool); /* Let svn clients know the creationdate of the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER, svn_time_to_cstring(slock->creation_date, resource->pool)); /* Let svn clients know the 'owner' of the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER, slock->owner); } *lock = dlock; return 0; }
/* ** Get the locks associated with the specified resource. ** ** If resolve_locks is true (non-zero), then any indirect locks are ** resolved to their actual, direct lock (i.e. the reference to followed ** to the original lock). ** ** The locks, if any, are returned as a linked list in no particular ** order. If no locks are present, then *locks will be NULL. ** ** #define DAV_GETLOCKS_RESOLVED 0 -- resolve indirects to directs ** #define DAV_GETLOCKS_PARTIAL 1 -- leave indirects partially filled ** #define DAV_GETLOCKS_COMPLETE 2 -- fill out indirect locks */ static dav_error * get_locks(dav_lockdb *lockdb, const dav_resource *resource, int calltype, dav_lock **locks) { dav_lockdb_private *info = lockdb->info; svn_error_t *serr; svn_lock_t *slock; dav_lock *lock = NULL; /* We only support exclusive locks, not shared ones. So this function always returns a "list" of exactly one lock, or just a NULL list. The 'calltype' arg is also meaningless, since we don't support locks on collections. */ /* Sanity check: if the resource has no associated path in the fs, then there's nothing to do. */ if (! resource->info->repos_path) { *locks = NULL; return 0; } /* The Big Lie: if the client ran 'svn lock', then we have to pretend that there's no existing lock. Otherwise mod_dav will throw '403 Locked' without even attempting to create a new lock. For the --force case, this is required and for the non-force case, we allow the filesystem to produce a better error for svn clients. */ if (info->r->method_number == M_LOCK) { *locks = NULL; return 0; } /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to check path for a lock.", resource->pool); if (slock != NULL) { svn_lock_to_dav_lock(&lock, slock, info->lock_break, resource->exists, resource->pool); /* Let svn clients know the creationdate of the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER, svn_time_to_cstring(slock->creation_date, resource->pool)); /* Let svn clients know who "owns" the slock. */ apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER, slock->owner); } *locks = lock; return 0; }
svn_error_t * svn_cl__print_status_xml(const char *path, svn_wc_status2_t *status, apr_pool_t *pool) { svn_stringbuf_t *sb = svn_stringbuf_create("", pool); apr_hash_t *att_hash; if (status->text_status == svn_wc_status_none && status->repos_text_status == svn_wc_status_none) return SVN_NO_ERROR; svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry", "path", svn_path_local_style(path, pool), NULL); att_hash = apr_hash_make(pool); apr_hash_set(att_hash, "item", APR_HASH_KEY_STRING, generate_status_desc(status->text_status)); apr_hash_set(att_hash, "props", APR_HASH_KEY_STRING, generate_status_desc(status->prop_status)); if (status->locked) apr_hash_set(att_hash, "wc-locked", APR_HASH_KEY_STRING, "true"); if (status->copied) apr_hash_set(att_hash, "copied", APR_HASH_KEY_STRING, "true"); if (status->switched) apr_hash_set(att_hash, "switched", APR_HASH_KEY_STRING, "true"); if (status->entry && ! status->entry->copied) apr_hash_set(att_hash, "revision", APR_HASH_KEY_STRING, apr_psprintf(pool, "%ld", status->entry->revision)); svn_xml_make_open_tag_hash(&sb, pool, svn_xml_normal, "wc-status", att_hash); if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev)) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "commit", "revision", apr_psprintf(pool, "%ld", status->entry->cmt_rev), NULL); svn_cl__xml_tagged_cdata(&sb, pool, "author", status->entry->cmt_author); if (status->entry->cmt_date) svn_cl__xml_tagged_cdata(&sb, pool, "date", svn_time_to_cstring (status->entry->cmt_date, pool)); svn_xml_make_close_tag(&sb, pool, "commit"); } if (status->entry && status->entry->lock_token) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL); svn_cl__xml_tagged_cdata(&sb, pool, "token", status->entry->lock_token); /* If lock_owner is NULL, assume WC is corrupt. */ if (status->entry->lock_owner) svn_cl__xml_tagged_cdata(&sb, pool, "owner", status->entry->lock_owner); else return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("'%s' has lock token, but no lock owner"), svn_path_local_style(path, pool)); svn_cl__xml_tagged_cdata(&sb, pool, "comment", status->entry->lock_comment); svn_cl__xml_tagged_cdata(&sb, pool, "created", svn_time_to_cstring (status->entry->lock_creation_date, pool)); svn_xml_make_close_tag(&sb, pool, "lock"); } svn_xml_make_close_tag(&sb, pool, "wc-status"); if (status->repos_text_status != svn_wc_status_none || status->repos_prop_status != svn_wc_status_none || status->repos_lock) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repos-status", "item", generate_status_desc(status->repos_text_status), "props", generate_status_desc(status->repos_prop_status), NULL); if (status->repos_lock) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL); svn_cl__xml_tagged_cdata(&sb, pool, "token", status->repos_lock->token); svn_cl__xml_tagged_cdata(&sb, pool, "owner", status->repos_lock->owner); svn_cl__xml_tagged_cdata(&sb, pool, "comment", status->repos_lock->comment); svn_cl__xml_tagged_cdata(&sb, pool, "created", svn_time_to_cstring (status->repos_lock->creation_date, pool)); if (status->repos_lock->expiration_date != 0) { svn_cl__xml_tagged_cdata(&sb, pool, "expires", svn_time_to_cstring (status->repos_lock->expiration_date, pool)); } svn_xml_make_close_tag(&sb, pool, "lock"); } svn_xml_make_close_tag(&sb, pool, "repos-status"); } svn_xml_make_close_tag(&sb, pool, "entry"); return svn_cl__error_checked_fputs(sb->data, stdout); }
void logger__log_error(logger_t *logger, svn_error_t *err, repository_t *repository, client_info_t *client_info) { if (logger && err) { const char *timestr, *continuation; const char *user, *repos, *remote_host; char errbuf[256]; /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */ char errstr[8192]; svn_error_clear(svn_mutex__lock(logger->mutex)); timestr = svn_time_to_cstring(apr_time_now(), logger->pool); remote_host = client_info && client_info->remote_host ? client_info->remote_host : "-"; user = client_info && client_info->user ? client_info->user : "******"; repos = repository && repository->repos_name ? repository->repos_name : "-"; continuation = ""; while (err) { const char *message = svn_err_best_message(err, errbuf, sizeof(errbuf)); /* based on httpd-2.2.4/server/log.c:log_error_core */ apr_size_t len = apr_snprintf(errstr, sizeof(errstr), "%" APR_PID_T_FMT " %s %s %s %s ERR%s %s %ld %d ", getpid(), timestr, remote_host, user, repos, continuation, err->file ? err->file : "-", err->line, err->apr_err); len += escape_errorlog_item(errstr + len, message, sizeof(errstr) - len); /* Truncate for the terminator (as apr_snprintf does) */ if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) { len = sizeof(errstr) - sizeof(APR_EOL_STR); } memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR)); len += sizeof(APR_EOL_STR) -1; /* add NL, ex terminating NUL */ svn_error_clear(svn_stream_write(logger->stream, errstr, &len)); continuation = "-"; err = err->child; } svn_pool_clear(logger->pool); svn_error_clear(svn_mutex__unlock(logger->mutex, SVN_NO_ERROR)); } }
/* Transmit LOCKS (a hash of Subversion filesystem locks keyed by path) across OUTPUT using BB. Use POOL for necessary allocations. NOTE: As written, this function currently returns one of only two status values -- "success", and "we had trouble writing out to the output stream". If you need to return something more interesting, you'll probably want to generate dav_error's here instead of passing back only apr_status_t's. */ static apr_status_t send_get_lock_response(apr_hash_t *locks, ap_filter_t *output, apr_bucket_brigade *bb, apr_pool_t *pool) { apr_pool_t *subpool; apr_hash_index_t *hi; /* start sending report */ SVN_APR_ERR(ap_fprintf(output, bb, DAV_XML_HEADER DEBUG_CR "<S:get-locks-report xmlns:S=\"" SVN_XML_NAMESPACE "\" xmlns:D=\"DAV:\">" DEBUG_CR)); /* stream the locks */ subpool = svn_pool_create(pool); for (hi = apr_hash_first(pool, locks); hi; hi = apr_hash_next(hi)) { void *val; const svn_lock_t *lock; svn_pool_clear(subpool); apr_hash_this(hi, NULL, NULL, &val); lock = val; /* Begin the <S:lock> tag, transmitting the path, token, and creation date. */ SVN_APR_ERR(ap_fprintf(output, bb, "<S:lock>" DEBUG_CR "<S:path>%s</S:path>" DEBUG_CR "<S:token>%s</S:token>" DEBUG_CR "<S:creationdate>%s</S:creationdate>" DEBUG_CR, apr_xml_quote_string(subpool, lock->path, 1), apr_xml_quote_string(subpool, lock->token, 1), svn_time_to_cstring(lock->creation_date, subpool))); /* Got expiration date? Tell the client. */ if (lock->expiration_date) SVN_APR_ERR(ap_fprintf(output, bb, "<S:expirationdate>%s</S:expirationdate>" DEBUG_CR, svn_time_to_cstring(lock->expiration_date, subpool))); /* Transmit the lock ownership information. */ if (lock->owner) { const char *owner; svn_boolean_t owner_base64 = FALSE; if (svn_xml_is_xml_safe(lock->owner, strlen(lock->owner))) { owner = apr_xml_quote_string(subpool, lock->owner, 1); } else { svn_string_t owner_string; const svn_string_t *encoded_owner; owner_string.data = lock->owner; owner_string.len = strlen(lock->owner); encoded_owner = svn_base64_encode_string2(&owner_string, TRUE, subpool); owner = encoded_owner->data; owner_base64 = TRUE; } SVN_APR_ERR(ap_fprintf(output, bb, "<S:owner %s>%s</S:owner>" DEBUG_CR, owner_base64 ? "encoding=\"base64\"" : "", owner)); } /* If the lock carries a comment, transmit that, too. */ if (lock->comment) { const char *comment; svn_boolean_t comment_base64 = FALSE; if (svn_xml_is_xml_safe(lock->comment, strlen(lock->comment))) { comment = apr_xml_quote_string(subpool, lock->comment, 1); } else { svn_string_t comment_string; const svn_string_t *encoded_comment; comment_string.data = lock->comment; comment_string.len = strlen(lock->comment); encoded_comment = svn_base64_encode_string2(&comment_string, TRUE, subpool); comment = encoded_comment->data; comment_base64 = TRUE; } SVN_APR_ERR(ap_fprintf(output, bb, "<S:comment %s>%s</S:comment>" DEBUG_CR, comment_base64 ? "encoding=\"base64\"" : "", comment)); } /* Okay, finish up this lock by closing the <S:lock> tag. */ SVN_APR_ERR(ap_fprintf(output, bb, "</S:lock>" DEBUG_CR)); } svn_pool_destroy(subpool); /* Finish the report */ SVN_APR_ERR(ap_fprintf(output, bb, "</S:get-locks-report>" DEBUG_CR)); return APR_SUCCESS; }
/* This implements the svn_client_list_func_t API, printing a single dirent in XML format. */ static svn_error_t * print_dirent_xml(void *baton, const char *path, const svn_dirent_t *dirent, const svn_lock_t *lock, const char *abs_path, apr_pool_t *pool) { struct print_baton *pb = baton; const char *entryname; svn_stringbuf_t *sb; if (strcmp(path, "") == 0) { if (dirent->kind == svn_node_file) entryname = svn_dirent_basename(abs_path, pool); else if (pb->verbose) entryname = "."; else /* Don't bother to list if no useful information will be shown. */ return SVN_NO_ERROR; } else entryname = path; if (pb->ctx->cancel_func) SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton)); sb = svn_stringbuf_create("", pool); svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry", "kind", svn_cl__node_kind_str_xml(dirent->kind), NULL); svn_cl__xml_tagged_cdata(&sb, pool, "name", entryname); if (dirent->kind == svn_node_file) { svn_cl__xml_tagged_cdata (&sb, pool, "size", apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT, dirent->size)); } svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "commit", "revision", apr_psprintf(pool, "%ld", dirent->created_rev), NULL); svn_cl__xml_tagged_cdata(&sb, pool, "author", dirent->last_author); if (dirent->time) svn_cl__xml_tagged_cdata(&sb, pool, "date", svn_time_to_cstring(dirent->time, pool)); svn_xml_make_close_tag(&sb, pool, "commit"); if (lock) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL); svn_cl__xml_tagged_cdata(&sb, pool, "token", lock->token); svn_cl__xml_tagged_cdata(&sb, pool, "owner", lock->owner); svn_cl__xml_tagged_cdata(&sb, pool, "comment", lock->comment); svn_cl__xml_tagged_cdata(&sb, pool, "created", svn_time_to_cstring(lock->creation_date, pool)); if (lock->expiration_date != 0) svn_cl__xml_tagged_cdata(&sb, pool, "expires", svn_time_to_cstring (lock->expiration_date, pool)); svn_xml_make_close_tag(&sb, pool, "lock"); } svn_xml_make_close_tag(&sb, pool, "entry"); return svn_cl__error_checked_fputs(sb->data, stdout); }
svn_error_t * svn_cl__print_status_xml(const char *cwd_abspath, const char *path, const svn_client_status_t *status, svn_client_ctx_t *ctx, apr_pool_t *pool) { svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool); apr_hash_t *att_hash; const char *local_abspath = status->local_abspath; svn_boolean_t tree_conflicted = FALSE; if (status->node_status == svn_wc_status_none && status->repos_node_status == svn_wc_status_none) return SVN_NO_ERROR; if (status->conflicted) SVN_ERR(svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted, ctx->wc_ctx, local_abspath, pool)); path = make_relpath(cwd_abspath, path, pool, pool); svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry", "path", svn_dirent_local_style(path, pool), NULL); att_hash = apr_hash_make(pool); svn_hash_sets(att_hash, "item", generate_status_desc(combined_status(status))); svn_hash_sets(att_hash, "props", generate_status_desc( (status->node_status != svn_wc_status_deleted) ? status->prop_status : svn_wc_status_none)); if (status->wc_is_locked) svn_hash_sets(att_hash, "wc-locked", "true"); if (status->copied) svn_hash_sets(att_hash, "copied", "true"); if (status->switched) svn_hash_sets(att_hash, "switched", "true"); if (status->file_external) svn_hash_sets(att_hash, "file-external", "true"); if (status->versioned && ! status->copied) svn_hash_sets(att_hash, "revision", apr_psprintf(pool, "%ld", status->revision)); if (tree_conflicted) svn_hash_sets(att_hash, "tree-conflicted", "true"); if (status->moved_from_abspath || status->moved_to_abspath) { const char *relpath; if (status->moved_from_abspath) { relpath = make_relpath(cwd_abspath, status->moved_from_abspath, pool, pool); relpath = svn_dirent_local_style(relpath, pool); svn_hash_sets(att_hash, "moved-from", relpath); } if (status->moved_to_abspath) { relpath = make_relpath(cwd_abspath, status->moved_to_abspath, pool, pool); relpath = svn_dirent_local_style(relpath, pool); svn_hash_sets(att_hash, "moved-to", relpath); } } svn_xml_make_open_tag_hash(&sb, pool, svn_xml_normal, "wc-status", att_hash); if (SVN_IS_VALID_REVNUM(status->changed_rev)) { svn_cl__print_xml_commit(&sb, status->changed_rev, status->changed_author, svn_time_to_cstring(status->changed_date, pool), pool); } if (status->lock) svn_cl__print_xml_lock(&sb, status->lock, pool); svn_xml_make_close_tag(&sb, pool, "wc-status"); if (status->repos_node_status != svn_wc_status_none || status->repos_lock) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repos-status", "item", generate_status_desc(combined_repos_status(status)), "props", generate_status_desc(status->repos_prop_status), NULL); if (status->repos_lock) svn_cl__print_xml_lock(&sb, status->repos_lock, pool); svn_xml_make_close_tag(&sb, pool, "repos-status"); } svn_xml_make_close_tag(&sb, pool, "entry"); return svn_cl__error_checked_fputs(sb->data, stdout); }
/* A callback of type svn_client_info_receiver2_t. Prints svn info in xml mode to standard out */ static svn_error_t * print_info_xml(void *baton, const char *target, const svn_client_info2_t *info, apr_pool_t *pool) { svn_stringbuf_t *sb = svn_stringbuf_create("", pool); const char *rev_str; const char *path_prefix = baton; if (SVN_IS_VALID_REVNUM(info->rev)) rev_str = apr_psprintf(pool, "%ld", info->rev); else rev_str = apr_pstrdup(pool, _("Resource is not under version control.")); /* "<entry ...>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry", "path", svn_cl__local_style_skip_ancestor( path_prefix, target, pool), "kind", svn_cl__node_kind_str_xml(info->kind), "revision", rev_str, NULL); svn_cl__xml_tagged_cdata(&sb, pool, "url", info->URL); if (info->repos_root_URL || info->repos_UUID) { /* "<repository>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repository", NULL); /* "<root> xx </root>" */ svn_cl__xml_tagged_cdata(&sb, pool, "root", info->repos_root_URL); /* "<uuid> xx </uuid>" */ svn_cl__xml_tagged_cdata(&sb, pool, "uuid", info->repos_UUID); /* "</repository>" */ svn_xml_make_close_tag(&sb, pool, "repository"); } if (info->wc_info) { /* "<wc-info>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "wc-info", NULL); /* "<wcroot-abspath> xx </wcroot-abspath>" */ if (info->wc_info->wcroot_abspath) svn_cl__xml_tagged_cdata(&sb, pool, "wcroot-abspath", info->wc_info->wcroot_abspath); /* "<schedule> xx </schedule>" */ svn_cl__xml_tagged_cdata(&sb, pool, "schedule", schedule_str(info->wc_info->schedule)); /* "<depth> xx </depth>" */ { svn_depth_t depth = info->wc_info->depth; /* In the entries world info just passed depth infinity for files */ if (depth == svn_depth_unknown && info->kind == svn_node_file) depth = svn_depth_infinity; svn_cl__xml_tagged_cdata(&sb, pool, "depth", svn_depth_to_word(depth)); } /* "<copy-from-url> xx </copy-from-url>" */ svn_cl__xml_tagged_cdata(&sb, pool, "copy-from-url", info->wc_info->copyfrom_url); /* "<copy-from-rev> xx </copy-from-rev>" */ if (SVN_IS_VALID_REVNUM(info->wc_info->copyfrom_rev)) svn_cl__xml_tagged_cdata(&sb, pool, "copy-from-rev", apr_psprintf(pool, "%ld", info->wc_info->copyfrom_rev)); /* "<text-updated> xx </text-updated>" */ if (info->wc_info->recorded_time) svn_cl__xml_tagged_cdata(&sb, pool, "text-updated", svn_time_to_cstring( info->wc_info->recorded_time, pool)); /* "<checksum> xx </checksum>" */ /* ### Print the checksum kind. */ svn_cl__xml_tagged_cdata(&sb, pool, "checksum", svn_checksum_to_cstring(info->wc_info->checksum, pool)); if (info->wc_info->changelist) /* "<changelist> xx </changelist>" */ svn_cl__xml_tagged_cdata(&sb, pool, "changelist", info->wc_info->changelist); /* "</wc-info>" */ svn_xml_make_close_tag(&sb, pool, "wc-info"); } if (info->last_changed_author || SVN_IS_VALID_REVNUM(info->last_changed_rev) || info->last_changed_date) { svn_cl__print_xml_commit(&sb, info->last_changed_rev, info->last_changed_author, svn_time_to_cstring(info->last_changed_date, pool), pool); } if (info->wc_info && info->wc_info->conflicts) { int i; for (i = 0; i < info->wc_info->conflicts->nelts; i++) { const svn_wc_conflict_description2_t *conflict = APR_ARRAY_IDX(info->wc_info->conflicts, i, const svn_wc_conflict_description2_t *); switch (conflict->kind) { case svn_wc_conflict_kind_text: /* "<conflict>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "conflict", NULL); /* "<prev-base-file> xx </prev-base-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "prev-base-file", conflict->base_abspath); /* "<prev-wc-file> xx </prev-wc-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "prev-wc-file", conflict->my_abspath); /* "<cur-base-file> xx </cur-base-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "cur-base-file", conflict->their_abspath); /* "</conflict>" */ svn_xml_make_close_tag(&sb, pool, "conflict"); break; case svn_wc_conflict_kind_property: /* "<conflict>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "conflict", NULL); /* "<prop-file> xx </prop-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "prop-file", conflict->their_abspath); /* "</conflict>" */ svn_xml_make_close_tag(&sb, pool, "conflict"); break; case svn_wc_conflict_kind_tree: SVN_ERR(svn_cl__append_tree_conflict_info_xml(sb, conflict, pool)); break; } } }
/* Write to DIGEST_PATH a representation of CHILDREN (which may be empty, if the versioned path in FS represented by DIGEST_PATH has no children) and LOCK (which may be NULL if that versioned path is lock itself locked). Set the permissions of DIGEST_PATH to those of PERMS_REFERENCE. Use POOL for all allocations. */ static svn_error_t * write_digest_file(apr_hash_t *children, svn_lock_t *lock, const char *fs_path, const char *digest_path, const char *perms_reference, apr_pool_t *pool) { svn_error_t *err = SVN_NO_ERROR; svn_stream_t *stream; apr_hash_index_t *hi; apr_hash_t *hash = apr_hash_make(pool); const char *tmp_path; SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs_path, PATH_LOCKS_DIR, pool), fs_path, pool)); SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_dirname(digest_path, pool), fs_path, pool)); if (lock) { const char *creation_date = NULL, *expiration_date = NULL; if (lock->creation_date) creation_date = svn_time_to_cstring(lock->creation_date, pool); if (lock->expiration_date) expiration_date = svn_time_to_cstring(lock->expiration_date, pool); hash_store(hash, PATH_KEY, sizeof(PATH_KEY)-1, lock->path, APR_HASH_KEY_STRING, pool); hash_store(hash, TOKEN_KEY, sizeof(TOKEN_KEY)-1, lock->token, APR_HASH_KEY_STRING, pool); hash_store(hash, OWNER_KEY, sizeof(OWNER_KEY)-1, lock->owner, APR_HASH_KEY_STRING, pool); hash_store(hash, COMMENT_KEY, sizeof(COMMENT_KEY)-1, lock->comment, APR_HASH_KEY_STRING, pool); hash_store(hash, IS_DAV_COMMENT_KEY, sizeof(IS_DAV_COMMENT_KEY)-1, lock->is_dav_comment ? "1" : "0", 1, pool); hash_store(hash, CREATION_DATE_KEY, sizeof(CREATION_DATE_KEY)-1, creation_date, APR_HASH_KEY_STRING, pool); hash_store(hash, EXPIRATION_DATE_KEY, sizeof(EXPIRATION_DATE_KEY)-1, expiration_date, APR_HASH_KEY_STRING, pool); } if (apr_hash_count(children)) { svn_stringbuf_t *children_list = svn_stringbuf_create("", pool); for (hi = apr_hash_first(pool, children); hi; hi = apr_hash_next(hi)) { svn_stringbuf_appendbytes(children_list, svn__apr_hash_index_key(hi), svn__apr_hash_index_klen(hi)); svn_stringbuf_appendbyte(children_list, '\n'); } hash_store(hash, CHILDREN_KEY, sizeof(CHILDREN_KEY)-1, children_list->data, children_list->len, pool); } SVN_ERR(svn_stream_open_unique(&stream, &tmp_path, svn_dirent_dirname(digest_path, pool), svn_io_file_del_none, pool, pool)); if ((err = svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool))) { svn_error_clear(svn_stream_close(stream)); return svn_error_createf(err->apr_err, err, _("Cannot write lock/entries hashfile '%s'"), svn_dirent_local_style(tmp_path, pool)); } SVN_ERR(svn_stream_close(stream)); SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool)); SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, pool)); return SVN_NO_ERROR; }
/* ** Append the specified lock(s) to the set of locks on this resource. ** ** If "make_indirect" is true (non-zero), then the specified lock(s) ** should be converted to an indirect lock (if it is a direct lock) ** before appending. Note that the conversion to an indirect lock does ** not alter the passed-in lock -- the change is internal the ** append_locks function. ** ** Multiple locks are specified using the lock->next links. */ static dav_error * append_locks(dav_lockdb *lockdb, const dav_resource *resource, int make_indirect, const dav_lock *lock) { dav_lockdb_private *info = lockdb->info; svn_lock_t *slock; svn_error_t *serr; dav_error *derr; /* If the resource's fs path is unreadable, we don't allow a lock to be created on it. */ if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM, resource->pool)) return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); if (lock->next) return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, DAV_ERR_LOCK_SAVE_LOCK, "Tried to attach multiple locks to a resource."); /* RFC2518bis (section 7.4) doesn't require us to support 'lock-null' resources at all. Instead, it asks that we treat 'LOCK nonexistentURL' as a PUT (followed by a LOCK) of a 0-byte file. */ if (! resource->exists) { svn_revnum_t rev, new_rev; svn_fs_txn_t *txn; svn_fs_root_t *txn_root; const char *conflict_msg; dav_svn_repos *repos = resource->info->repos; apr_hash_t *revprop_table = apr_hash_make(resource->pool); apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING, svn_string_create(repos->username, resource->pool)); if (resource->info->repos->is_svn_client) return dav_svn__new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED, DAV_ERR_LOCK_SAVE_LOCK, "Subversion clients may not lock " "nonexistent paths."); else if (! resource->info->repos->autoversioning) return dav_svn__new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED, DAV_ERR_LOCK_SAVE_LOCK, "Attempted to lock non-existent path; " "turn on autoversioning first."); /* Commit a 0-byte file: */ if ((serr = svn_fs_youngest_rev(&rev, repos->fs, resource->pool))) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not determine youngest revision", resource->pool); if ((serr = svn_repos_fs_begin_txn_for_commit2(&txn, repos->repos, rev, revprop_table, resource->pool))) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not begin a transaction", resource->pool); if ((serr = svn_fs_txn_root(&txn_root, txn, resource->pool))) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not begin a transaction", resource->pool); if ((serr = svn_fs_make_file(txn_root, resource->info->repos_path, resource->pool))) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not create empty file.", resource->pool); if ((serr = dav_svn__attach_auto_revprops(txn, resource->info->repos_path, resource->pool))) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not create empty file.", resource->pool); serr = svn_repos_fs_commit_txn(&conflict_msg, repos->repos, &new_rev, txn, resource->pool); if (SVN_IS_VALID_REVNUM(new_rev)) { /* ### Log an error in post commit FS processing? */ svn_error_clear(serr); } else { svn_error_clear(svn_fs_abort_txn(txn, resource->pool)); if (serr) return dav_svn__convert_err(serr, HTTP_CONFLICT, apr_psprintf(resource->pool, "Conflict when " "committing '%s'.", conflict_msg), resource->pool); else return dav_svn__new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Commit failed but there was no error " "provided."); } } /* Convert the dav_lock into an svn_lock_t. */ derr = dav_lock_to_svn_lock(&slock, lock, resource->info->repos_path, info, resource->info->repos->is_svn_client, resource->pool); if (derr) return derr; /* Now use the svn_lock_t to actually perform the lock. */ serr = svn_repos_fs_lock(&slock, resource->info->repos->repos, slock->path, slock->token, slock->comment, slock->is_dav_comment, slock->expiration_date, info->working_revnum, info->lock_steal, resource->pool); if (serr && serr->apr_err == SVN_ERR_FS_NO_USER) { svn_error_clear(serr); return dav_svn__new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock creation is not allowed."); } else if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to create new lock.", resource->pool); /* A standard webdav LOCK response doesn't include any information about the creation date. We send it in a custom header, so that svn clients can fill in svn_lock_t->creation_date. A generic DAV client should just ignore the header. */ apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER, svn_time_to_cstring(slock->creation_date, resource->pool)); /* A standard webdav LOCK response doesn't include any information about the owner of the lock. ('DAV:owner' has nothing to do with authorization, it's just a comment that we map to svn_lock_t->comment.) We send the owner in a custom header, so that svn clients can fill in svn_lock_t->owner. A generic DAV client should just ignore the header. */ apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER, slock->owner); /* Log the locking as a 'high-level' action. */ dav_svn__operational_log(resource->info, svn_log__lock_one_path(slock->path, info->lock_steal, resource->info->r->pool)); return 0; }
/* A callback of type svn_info_receiver_t. Prints svn info in xml mode to standard out */ static svn_error_t * print_info_xml(void *baton, const char *target, const svn_info_t *info, apr_pool_t *pool) { svn_stringbuf_t *sb = svn_stringbuf_create("", pool); const char *rev_str; if (SVN_IS_VALID_REVNUM(info->rev)) rev_str = apr_psprintf(pool, "%ld", info->rev); else rev_str = apr_pstrdup(pool, _("Resource is not under version control.")); /* "<entry ...>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry", "path", svn_path_local_style(target, pool), "kind", svn_cl__node_kind_str_xml(info->kind), "revision", rev_str, NULL); svn_cl__xml_tagged_cdata(&sb, pool, "url", info->URL); if (info->repos_root_URL || info->repos_UUID) { /* "<repository>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repository", NULL); /* "<root> xx </root>" */ svn_cl__xml_tagged_cdata(&sb, pool, "root", info->repos_root_URL); /* "<uuid> xx </uuid>" */ svn_cl__xml_tagged_cdata(&sb, pool, "uuid", info->repos_UUID); /* "</repository>" */ svn_xml_make_close_tag(&sb, pool, "repository"); } if (info->has_wc_info) { /* "<wc-info>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "wc-info", NULL); /* "<schedule> xx </schedule>" */ svn_cl__xml_tagged_cdata(&sb, pool, "schedule", schedule_str(info->schedule)); /* "<depth> xx </depth>" */ svn_cl__xml_tagged_cdata(&sb, pool, "depth", svn_depth_to_word(info->depth)); /* "<copy-from-url> xx </copy-from-url>" */ svn_cl__xml_tagged_cdata(&sb, pool, "copy-from-url", info->copyfrom_url); /* "<copy-from-rev> xx </copy-from-rev>" */ if (SVN_IS_VALID_REVNUM(info->copyfrom_rev)) svn_cl__xml_tagged_cdata(&sb, pool, "copy-from-rev", apr_psprintf(pool, "%ld", info->copyfrom_rev)); /* "<text-updated> xx </text-updated>" */ if (info->text_time) svn_cl__xml_tagged_cdata(&sb, pool, "text-updated", svn_time_to_cstring(info->text_time, pool)); /* "<checksum> xx </checksum>" */ svn_cl__xml_tagged_cdata(&sb, pool, "checksum", info->checksum); if (info->changelist) /* "<changelist> xx </changelist>" */ svn_cl__xml_tagged_cdata(&sb, pool, "changelist", info->changelist); /* "</wc-info>" */ svn_xml_make_close_tag(&sb, pool, "wc-info"); } if (info->last_changed_author || SVN_IS_VALID_REVNUM(info->last_changed_rev) || info->last_changed_date) { svn_cl__print_xml_commit(&sb, info->last_changed_rev, info->last_changed_author, svn_time_to_cstring(info->last_changed_date, pool), pool); } if (info->conflict_old || info->conflict_wrk || info->conflict_new || info->prejfile) { /* "<conflict>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "conflict", NULL); /* "<prev-base-file> xx </prev-base-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "prev-base-file", info->conflict_old); /* "<prev-wc-file> xx </prev-wc-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "prev-wc-file", info->conflict_wrk); /* "<cur-base-file> xx </cur-base-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "cur-base-file", info->conflict_new); /* "<prop-file> xx </prop-file>" */ svn_cl__xml_tagged_cdata(&sb, pool, "prop-file", info->prejfile); /* "</conflict>" */ svn_xml_make_close_tag(&sb, pool, "conflict"); } if (info->lock) { /* "<lock>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL); /* "<token> xx </token>" */ svn_cl__xml_tagged_cdata(&sb, pool, "token", info->lock->token); /* "<owner> xx </owner>" */ svn_cl__xml_tagged_cdata(&sb, pool, "owner", info->lock->owner); /* "<comment ...> xxxx </comment>" */ svn_cl__xml_tagged_cdata(&sb, pool, "comment", info->lock->comment); /* "<created> xx </created>" */ svn_cl__xml_tagged_cdata(&sb, pool, "created", svn_time_to_cstring (info->lock->creation_date, pool)); /* "<expires> xx </expires>" */ svn_cl__xml_tagged_cdata(&sb, pool, "expires", svn_time_to_cstring (info->lock->expiration_date, pool)); /* "</lock>" */ svn_xml_make_close_tag(&sb, pool, "lock"); } if (info->tree_conflict) SVN_ERR(svn_cl__append_tree_conflict_info_xml(sb, info->tree_conflict, pool)); /* "</entry>" */ svn_xml_make_close_tag(&sb, pool, "entry"); return svn_cl__error_checked_fputs(sb->data, stdout); }