Modified: subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/gpg_agent.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/gpg_agent.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/gpg_agent.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/gpg_agent.c Sun Dec 14 11:52:14 2014 @@ -72,6 +72,9 @@ #include "svn_cmdline.h" #include "svn_checksum.h" #include "svn_string.h" +#include "svn_hash.h" +#include "svn_user.h" +#include "svn_dirent_uri.h" #include "private/svn_auth_private.h" @@ -80,6 +83,7 @@ #ifdef SVN_HAVE_GPG_AGENT #define BUFFER_SIZE 1024 +#define ATTEMPT_PARAMETER "svn.simple.gpg_agent.attempt" /* Modify STR in-place such that blanks are escaped as required by the * gpg-agent protocol. Return a pointer to STR. */ @@ -98,6 +102,24 @@ escape_blanks(char *str) return str; } +/* Generate the string CACHE_ID_P based on the REALMSTRING allocated in + * RESULT_POOL using SCRATCH_POOL for temporary allocations. This is similar + * to other password caching mechanisms. */ +static svn_error_t * +get_cache_id(const char **cache_id_p, const char *realmstring, + apr_pool_t *scratch_pool, apr_pool_t *result_pool) +{ + const char *cache_id = NULL; + svn_checksum_t *digest = NULL; + + SVN_ERR(svn_checksum(&digest, svn_checksum_md5, realmstring, + strlen(realmstring), scratch_pool)); + cache_id = svn_checksum_to_cstring(digest, result_pool); + *cache_id_p = cache_id; + + return SVN_NO_ERROR; +} + /* Attempt to read a gpg-agent response message from the socket SD into * buffer BUF. Buf is assumed to be N bytes large. Return TRUE if a response * message could be read that fits into the buffer. Else return FALSE. @@ -156,6 +178,17 @@ send_option(int sd, char *buf, size_t n, return (strncmp(buf, "OK", 2) == 0); } +/* Send the BYE command and disconnect from the gpg-agent. Doing this avoids + * gpg-agent emitting a "Connection reset by peer" log message with some + * versions of gpg-agent. */ +static void +bye_gpg_agent(int sd) +{ + /* don't bother to check the result of the write, it either worked or it + * didn't, but either way we're closing. */ + write(sd, "BYE\n", 4); + close(sd); +} /* Locate a running GPG Agent, and return an open file descriptor * for communication with the agent in *NEW_SD. If no running agent @@ -173,17 +206,34 @@ find_running_gpg_agent(int *new_sd, apr_ *new_sd = -1; + /* This implements the method of finding the socket as described in + * the gpg-agent man page under the --use-standard-socket option. + * The manage page misleadingly says the standard socket is + * "named 'S.gpg-agent' located in the home directory." The standard + * socket path is actually in the .gnupg directory in the home directory, + * i.e. ~/.gnupg/S.gpg-agent */ gpg_agent_info = getenv("GPG_AGENT_INFO"); if (gpg_agent_info != NULL) { apr_array_header_t *socket_details; + /* For reference GPG_AGENT_INFO consists of 3 : separated fields. + * The path to the socket, the pid of the gpg-agent process and + * finally the version of the protocol the agent talks. */ socket_details = svn_cstring_split(gpg_agent_info, ":", TRUE, pool); socket_name = APR_ARRAY_IDX(socket_details, 0, const char *); } else - return SVN_NO_ERROR; + { + const char *homedir = svn_user_get_homedir(pool); + + if (!homedir) + return SVN_NO_ERROR; + + socket_name = svn_dirent_join_many(pool, homedir, ".gnupg", + "S.gpg-agent", NULL); + } if (socket_name != NULL) { @@ -210,13 +260,13 @@ find_running_gpg_agent(int *new_sd, apr_ buffer = apr_palloc(pool, BUFFER_SIZE); if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE)) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } if (strncmp(buffer, "OK", 2) != 0) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } @@ -226,19 +276,19 @@ find_running_gpg_agent(int *new_sd, apr_ request = "GETINFO socket_name\n"; if (write(sd, request, strlen(request)) == -1) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE)) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } if (strncmp(buffer, "D", 1) == 0) p = &buffer[2]; if (!p) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } ep = strchr(p, '\n'); @@ -246,18 +296,18 @@ find_running_gpg_agent(int *new_sd, apr_ *ep = '\0'; if (strcmp(socket_name, p) != 0) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } /* The agent will terminate its response with "OK". */ if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE)) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } if (strncmp(buffer, "OK", 2) != 0) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } @@ -265,60 +315,28 @@ find_running_gpg_agent(int *new_sd, apr_ return SVN_NO_ERROR; } -/* Implementation of svn_auth__password_get_t that retrieves the password - from gpg-agent */ -static svn_error_t * -password_get_gpg_agent(svn_boolean_t *done, - const char **password, - apr_hash_t *creds, - const char *realmstring, - const char *username, - apr_hash_t *parameters, - svn_boolean_t non_interactive, - apr_pool_t *pool) +static svn_boolean_t +send_options(int sd, char *buf, size_t n, apr_pool_t *scratch_pool) { - int sd; - const char *p = NULL; - char *ep = NULL; - char *buffer; - const char *request = NULL; - const char *cache_id = NULL; const char *tty_name; const char *tty_type; const char *lc_ctype; const char *display; - svn_checksum_t *digest = NULL; - char *password_prompt; - char *realm_prompt; - - *done = FALSE; - - SVN_ERR(find_running_gpg_agent(&sd, pool)); - if (sd == -1) - return SVN_NO_ERROR; - - buffer = apr_palloc(pool, BUFFER_SIZE); /* Send TTY_NAME to the gpg-agent daemon. */ tty_name = getenv("GPG_TTY"); if (tty_name != NULL) { - if (!send_option(sd, buffer, BUFFER_SIZE, "ttyname", tty_name, pool)) - { - close(sd); - return SVN_NO_ERROR; - } + if (!send_option(sd, buf, n, "ttyname", tty_name, scratch_pool)) + return FALSE; } /* Send TTY_TYPE to the gpg-agent daemon. */ tty_type = getenv("TERM"); if (tty_type != NULL) { - if (!send_option(sd, buffer, BUFFER_SIZE, "ttytype", tty_type, pool)) - { - close(sd); - return SVN_NO_ERROR; - } + if (!send_option(sd, buf, n, "ttytype", tty_type, scratch_pool)) + return FALSE; } /* Compute LC_CTYPE. */ @@ -331,53 +349,92 @@ password_get_gpg_agent(svn_boolean_t *do /* Send LC_CTYPE to the gpg-agent daemon. */ if (lc_ctype != NULL) { - if (!send_option(sd, buffer, BUFFER_SIZE, "lc-ctype", lc_ctype, pool)) - { - close(sd); - return SVN_NO_ERROR; - } + if (!send_option(sd, buf, n, "lc-ctype", lc_ctype, scratch_pool)) + return FALSE; } /* Send DISPLAY to the gpg-agent daemon. */ display = getenv("DISPLAY"); if (display != NULL) { - if (!send_option(sd, buffer, BUFFER_SIZE, "display", display, pool)) - { - close(sd); - return SVN_NO_ERROR; - } + if (!send_option(sd, buf, n, "display", display, scratch_pool)) + return FALSE; } - /* Create the CACHE_ID which will be generated based on REALMSTRING similar - to other password caching mechanisms. */ - SVN_ERR(svn_checksum(&digest, svn_checksum_md5, realmstring, - strlen(realmstring), pool)); - cache_id = svn_checksum_to_cstring(digest, pool); + return TRUE; +} + +/* Implementation of svn_auth__password_get_t that retrieves the password + from gpg-agent */ +static svn_error_t * +password_get_gpg_agent(svn_boolean_t *done, + const char **password, + apr_hash_t *creds, + const char *realmstring, + const char *username, + apr_hash_t *parameters, + svn_boolean_t non_interactive, + apr_pool_t *pool) +{ + int sd; + const char *p = NULL; + char *ep = NULL; + char *buffer; + const char *request = NULL; + const char *cache_id = NULL; + char *password_prompt; + char *realm_prompt; + char *error_prompt; + int *attempt; + + *done = FALSE; + + attempt = svn_hash_gets(parameters, ATTEMPT_PARAMETER); + + SVN_ERR(find_running_gpg_agent(&sd, pool)); + if (sd == -1) + return SVN_NO_ERROR; + + buffer = apr_palloc(pool, BUFFER_SIZE); + + if (!send_options(sd, buffer, BUFFER_SIZE, pool)) + { + bye_gpg_agent(sd); + return SVN_NO_ERROR; + } + + SVN_ERR(get_cache_id(&cache_id, realmstring, pool, pool)); password_prompt = apr_psprintf(pool, _("Password for '%s': "), username); realm_prompt = apr_psprintf(pool, _("Enter your Subversion password for %s"), realmstring); + if (*attempt == 1) + /* X means no error to the gpg-agent protocol */ + error_prompt = apr_pstrdup(pool, "X"); + else + error_prompt = apr_pstrdup(pool, _("Authentication failed")); + request = apr_psprintf(pool, - "GET_PASSPHRASE --data %s--repeat=1 " - "%s X %s %s\n", + "GET_PASSPHRASE --data %s" + "%s %s %s %s\n", non_interactive ? "--no-ask " : "", cache_id, + escape_blanks(error_prompt), escape_blanks(password_prompt), escape_blanks(realm_prompt)); if (write(sd, request, strlen(request)) == -1) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE)) { - close(sd); + bye_gpg_agent(sd); return SVN_NO_ERROR; } - close(sd); + bye_gpg_agent(sd); if (strncmp(buffer, "ERR", 3) == 0) return SVN_NO_ERROR; @@ -424,7 +481,7 @@ password_set_gpg_agent(svn_boolean_t *do if (sd == -1) return SVN_NO_ERROR; - close(sd); + bye_gpg_agent(sd); *done = TRUE; return SVN_NO_ERROR; @@ -440,11 +497,108 @@ simple_gpg_agent_first_creds(void **cred const char *realmstring, apr_pool_t *pool) { - return svn_auth__simple_creds_cache_get(credentials, iter_baton, - provider_baton, parameters, - realmstring, password_get_gpg_agent, - SVN_AUTH__GPG_AGENT_PASSWORD_TYPE, - pool); + svn_error_t *err; + int *attempt = apr_palloc(pool, sizeof(*attempt)); + + *attempt = 1; + svn_hash_sets(parameters, ATTEMPT_PARAMETER, attempt); + err = svn_auth__simple_creds_cache_get(credentials, iter_baton, + provider_baton, parameters, + realmstring, password_get_gpg_agent, + SVN_AUTH__GPG_AGENT_PASSWORD_TYPE, + pool); + *iter_baton = attempt; + + return err; +} + +/* An implementation of svn_auth_provider_t::next_credentials() */ +static svn_error_t * +simple_gpg_agent_next_creds(void **credentials, + void *iter_baton, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool) +{ + int *attempt = (int *)iter_baton; + int sd; + char *buffer; + const char *cache_id = NULL; + const char *request = NULL; + + *credentials = NULL; + + /* The users previous credentials failed so first remove the cached entry, + * before trying to retrieve them again. Because gpg-agent stores cached + * credentials immediately upon retrieving them, this gives us the + * opportunity to remove the invalid credentials and prompt the + * user again. While it's possible that server side issues could trigger + * this, this cache is ephemeral so at worst we're just speeding up + * when the user would need to re-enter their password. */ + + if (svn_hash_gets(parameters, SVN_AUTH_PARAM_NON_INTERACTIVE)) + { + /* In this case since we're running non-interactively we do not + * want to clear the cache since the user was never prompted by + * gpg-agent to set a password. */ + return SVN_NO_ERROR; + } + + *attempt = *attempt + 1; + + SVN_ERR(find_running_gpg_agent(&sd, pool)); + if (sd == -1) + return SVN_NO_ERROR; + + buffer = apr_palloc(pool, BUFFER_SIZE); + + if (!send_options(sd, buffer, BUFFER_SIZE, pool)) + { + bye_gpg_agent(sd); + return SVN_NO_ERROR; + } + + SVN_ERR(get_cache_id(&cache_id, realmstring, pool, pool)); + + request = apr_psprintf(pool, "CLEAR_PASSPHRASE %s\n", cache_id); + + if (write(sd, request, strlen(request)) == -1) + { + bye_gpg_agent(sd); + return SVN_NO_ERROR; + } + + if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE)) + { + bye_gpg_agent(sd); + return SVN_NO_ERROR; + } + + if (strncmp(buffer, "OK\n", 3) != 0) + { + bye_gpg_agent(sd); + return SVN_NO_ERROR; + } + + /* TODO: This attempt limit hard codes it at 3 attempts (or 2 retries) + * which matches svn command line client's retry_limit as set in + * svn_cmdline_create_auth_baton(). It would be nice to have that + * limit reflected here but that violates the boundry between the + * prompt provider and the cache provider. gpg-agent is acting as + * both here due to the peculiarties of their design so we'll have to + * live with this for now. Note that when these failures get exceeded + * it'll eventually fall back on the retry limits of whatever prompt + * provider is in effect, so this effectively doubles the limit. */ + if (*attempt < 4) + return svn_auth__simple_creds_cache_get(credentials, &iter_baton, + provider_baton, parameters, + realmstring, + password_get_gpg_agent, + SVN_AUTH__GPG_AGENT_PASSWORD_TYPE, + pool); + + return SVN_NO_ERROR; } @@ -468,7 +622,7 @@ simple_gpg_agent_save_creds(svn_boolean_ static const svn_auth_provider_t gpg_agent_simple_provider = { SVN_AUTH_CRED_SIMPLE, simple_gpg_agent_first_creds, - NULL, + simple_gpg_agent_next_creds, simple_gpg_agent_save_creds };
Modified: subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/io.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/io.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/io.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/libsvn_subr/io.c Sun Dec 14 11:52:14 2014 @@ -4675,8 +4675,25 @@ svn_io_open_unique_file3(apr_file_t **fi * case, but only if the umask allows it. */ if (!using_system_temp_dir) { + svn_error_t *err; + SVN_ERR(merge_default_file_perms(tempfile, &perms, scratch_pool)); - SVN_ERR(file_perms_set2(tempfile, perms, scratch_pool)); + err = file_perms_set2(tempfile, perms, scratch_pool); + if (err) + { + if (APR_STATUS_IS_INCOMPLETE(err->apr_err) || + APR_STATUS_IS_ENOTIMPL(err->apr_err)) + svn_error_clear(err); + else + { + const char *message; + message = apr_psprintf(scratch_pool, + _("Can't set permissions on '%s'"), + svn_dirent_local_style(tempname, + scratch_pool)); + return svn_error_quick_wrap(err, message); + } + } } #endif Modified: subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/cleanup.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/cleanup.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/cleanup.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/cleanup.c Sun Dec 14 11:52:14 2014 @@ -67,69 +67,13 @@ can_be_cleaned(int *wc_format, return SVN_NO_ERROR; } -/* Do a modifed check for LOCAL_ABSPATH, and all working children, to force - timestamp repair. */ +/* Dummy svn_wc_status_func4_t implementation */ static svn_error_t * -repair_timestamps(svn_wc__db_t *db, - const char *local_abspath, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) +status_dummy_callback(void *baton, + const char *local_abspath, + const svn_wc_status3_t *status, + apr_pool_t *scratch_pool) { - svn_node_kind_t kind; - svn_wc__db_status_t status; - - if (cancel_func) - SVN_ERR(cancel_func(cancel_baton)); - - SVN_ERR(svn_wc__db_read_info(&status, &kind, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, - db, local_abspath, scratch_pool, scratch_pool)); - - if (status == svn_wc__db_status_server_excluded - || status == svn_wc__db_status_deleted - || status == svn_wc__db_status_excluded - || status == svn_wc__db_status_not_present) - return SVN_NO_ERROR; - - if (kind == svn_node_file - || kind == svn_node_symlink) - { - svn_boolean_t modified; - SVN_ERR(svn_wc__internal_file_modified_p(&modified, - db, local_abspath, FALSE, - scratch_pool)); - } - else if (kind == svn_node_dir) - { - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - const apr_array_header_t *children; - int i; - - SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db, - local_abspath, - scratch_pool, - iterpool)); - for (i = 0; i < children->nelts; ++i) - { - const char *child_abspath; - - svn_pool_clear(iterpool); - - child_abspath = svn_dirent_join(local_abspath, - APR_ARRAY_IDX(children, i, - const char *), - iterpool); - - SVN_ERR(repair_timestamps(db, child_abspath, - cancel_func, cancel_baton, iterpool)); - } - svn_pool_destroy(iterpool); - } - return SVN_NO_ERROR; } @@ -184,8 +128,17 @@ cleanup_internal(svn_wc__db_t *db, SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool)); } - SVN_ERR(repair_timestamps(db, dir_abspath, cancel_func, cancel_baton, - scratch_pool)); + /* Instead of implementing a separate repair step here, use the standard + status walker's optimized implementation, which performs repairs when + there is a lock. */ + SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity, + FALSE /* get_all */, + FALSE /* no_ignore */, + FALSE /* ignore_text_mods */, + NULL /* ignore patterns */, + status_dummy_callback, NULL, + cancel_func, cancel_baton, + scratch_pool)); /* All done, toss the lock */ SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool)); Modified: subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff.h URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff.h?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff.h (original) +++ subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff.h Sun Dec 14 11:52:14 2014 @@ -47,9 +47,6 @@ extern "C" { svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine version of LOCAL_ABSPATH as ADDED. In this case an svn_wc__db_status_deleted may shadow an added or deleted node. - - If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not - in the changelist, don't report the node. */ svn_error_t * svn_wc__diff_local_only_file(svn_wc__db_t *db, @@ -57,7 +54,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ const char *relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, - apr_hash_t *changelist_hash, svn_boolean_t diff_pristine, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -73,9 +69,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine version of LOCAL_ABSPATH as ADDED. In this case an svn_wc__db_status_deleted may shadow an added or deleted node. - - If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not - in the changelist, don't report the node. */ svn_error_t * svn_wc__diff_local_only_dir(svn_wc__db_t *db, @@ -84,7 +77,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t svn_depth_t depth, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, - apr_hash_t *changelist_hash, svn_boolean_t diff_pristine, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -132,7 +124,6 @@ svn_wc__diff_base_working_diff(svn_wc__d const char *local_abspath, const char *relpath, svn_revnum_t revision, - apr_hash_t *changelist_hash, const svn_diff_tree_processor_t *processor, void *processor_dir_baton, svn_boolean_t diff_pristine, @@ -140,6 +131,32 @@ svn_wc__diff_base_working_diff(svn_wc__d void *cancel_baton, apr_pool_t *scratch_pool); +/* Return a tree processor filter that filters by changelist membership. + * + * This filter only passes on the changes for a file if the file's path + * (in the WC) is assigned to one of the changelists in @a changelist_hash. + * It also passes on the opening and closing of each directory that contains + * such a change, and possibly also of other directories, but not addition + * or deletion or changes to a directory. + * + * If @a changelist_hash is null then no filtering is performed and the + * returned diff processor is driven exactly like the input @a processor. + * + * @a wc_ctx is the WC context and @a root_local_abspath is the WC path of + * the root of the diff (for which relpath = "" in the diff processor). + * + * Allocate the returned diff processor in @a result_pool, or if no + * filtering is required then the input pointer @a processor itself may be + * returned. + */ +const svn_diff_tree_processor_t * +svn_wc__changelist_filter_tree_processor_create( + const svn_diff_tree_processor_t *processor, + svn_wc_context_t *wc_ctx, + const char *root_local_abspath, + apr_hash_t *changelist_hash, + apr_pool_t *result_pool); + #ifdef __cplusplus } Modified: subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_editor.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_editor.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_editor.c Sun Dec 14 11:52:14 2014 @@ -114,9 +114,6 @@ struct edit_baton_t /* Possibly diff repos against text-bases instead of working files. */ svn_boolean_t diff_pristine; - /* Hash whose keys are const char * changelist names. */ - apr_hash_t *changelist_hash; - /* Cancel function/baton */ svn_cancel_func_t cancel_func; void *cancel_baton; @@ -238,43 +235,26 @@ struct file_baton_t * calculating diffs. USE_TEXT_BASE defines whether to compare * against working files or text-bases. REVERSE_ORDER defines which * direction to perform the diff. - * - * CHANGELIST_FILTER is a list of const char * changelist names, used to - * filter diff output responses to only those items in one of the - * specified changelists, empty (or NULL altogether) if no changelist - * filtering is requested. */ static svn_error_t * make_edit_baton(struct edit_baton_t **edit_baton, svn_wc__db_t *db, const char *anchor_abspath, const char *target, - const svn_wc_diff_callbacks4_t *callbacks, - void *callback_baton, + const svn_diff_tree_processor_t *processor, svn_depth_t depth, svn_boolean_t ignore_ancestry, svn_boolean_t show_copies_as_adds, svn_boolean_t use_text_base, svn_boolean_t reverse_order, - const apr_array_header_t *changelist_filter, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { - apr_hash_t *changelist_hash = NULL; struct edit_baton_t *eb; - const svn_diff_tree_processor_t *processor; SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath)); - if (changelist_filter && changelist_filter->nelts) - SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, - pool)); - - SVN_ERR(svn_wc__wrap_diff_callbacks(&processor, - callbacks, callback_baton, TRUE, - pool, pool)); - if (reverse_order) processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool); @@ -295,7 +275,6 @@ make_edit_baton(struct edit_baton_t **ed eb->ignore_ancestry = ignore_ancestry; eb->local_before_remote = reverse_order; eb->diff_pristine = use_text_base; - eb->changelist_hash = changelist_hash; eb->cancel_func = cancel_func; eb->cancel_baton = cancel_baton; eb->pool = pool; @@ -409,7 +388,6 @@ svn_wc__diff_base_working_diff(svn_wc__d const char *local_abspath, const char *relpath, svn_revnum_t revision, - apr_hash_t *changelist_hash, const svn_diff_tree_processor_t *processor, void *processor_dir_baton, svn_boolean_t diff_pristine, @@ -436,12 +414,11 @@ svn_wc__diff_base_working_diff(svn_wc__d apr_hash_t *base_props; apr_hash_t *local_props; apr_array_header_t *prop_changes; - const char *changelist; SVN_ERR(svn_wc__db_read_info(&status, NULL, &db_revision, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &working_checksum, NULL, NULL, NULL, NULL, NULL, NULL, &recorded_size, - &recorded_time, &changelist, NULL, NULL, + &recorded_time, NULL, NULL, NULL, &had_props, &props_mod, NULL, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); checksum = working_checksum; @@ -450,12 +427,6 @@ svn_wc__diff_base_working_diff(svn_wc__d || status == svn_wc__db_status_added || (status == svn_wc__db_status_deleted && diff_pristine)); - /* If the item is not a member of a specified changelist (and there are - some specified changelists), skip it. */ - if (changelist_hash && !svn_hash_gets(changelist_hash, changelist)) - return SVN_NO_ERROR; - - if (status != svn_wc__db_status_normal) { SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db_revision, @@ -780,7 +751,6 @@ walk_local_nodes_diff(struct edit_baton_ SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -790,7 +760,6 @@ walk_local_nodes_diff(struct edit_baton_ child_relpath, depth_below_here, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -826,7 +795,6 @@ walk_local_nodes_diff(struct edit_baton_ db, child_abspath, child_relpath, eb->revnum, - eb->changelist_hash, eb->processor, dir_baton, eb->diff_pristine, eb->cancel_func, @@ -849,7 +817,6 @@ walk_local_nodes_diff(struct edit_baton_ SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -858,7 +825,6 @@ walk_local_nodes_diff(struct edit_baton_ SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, child_relpath, depth_below_here, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -870,13 +836,9 @@ walk_local_nodes_diff(struct edit_baton_ if (compared) return SVN_NO_ERROR; - /* Check for local property mods on this directory, if we haven't - already reported them and we aren't changelist-filted. - ### it should be noted that we do not currently allow directories - ### to be part of changelists, so if a changelist is provided, the - ### changelist check will always fail. */ + /* Check for local property mods on this directory, if we haven't + already reported them. */ if (! skip - && ! eb->changelist_hash && ! in_anchor_not_target && props_mod) { @@ -919,7 +881,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ const char *relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, - apr_hash_t *changelist_hash, svn_boolean_t diff_pristine, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -932,7 +893,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ const svn_checksum_t *checksum; const char *original_repos_relpath; svn_revnum_t original_revision; - const char *changelist; svn_boolean_t had_props; svn_boolean_t props_mod; apr_hash_t *pristine_props; @@ -948,7 +908,7 @@ svn_wc__diff_local_only_file(svn_wc__db_ NULL, NULL, NULL, NULL, &checksum, NULL, &original_repos_relpath, NULL, NULL, &original_revision, NULL, NULL, NULL, - &changelist, NULL, NULL, &had_props, + NULL, NULL, NULL, &had_props, &props_mod, NULL, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); @@ -959,10 +919,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ || (status == svn_wc__db_status_deleted && diff_pristine))); - if (changelist && changelist_hash - && !svn_hash_gets(changelist_hash, changelist)) - return SVN_NO_ERROR; - if (status == svn_wc__db_status_deleted) { assert(diff_pristine); @@ -1065,7 +1021,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t svn_depth_t depth, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, - apr_hash_t *changelist_hash, svn_boolean_t diff_pristine, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -1094,6 +1049,7 @@ svn_wc__diff_local_only_dir(svn_wc__db_t processor_parent_baton, processor, scratch_pool, iterpool)); + /* ### skip_children is not used */ SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, local_abspath, scratch_pool, iterpool)); @@ -1138,7 +1094,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, processor, pdb, - changelist_hash, diff_pristine, cancel_func, cancel_baton, scratch_pool)); @@ -1150,7 +1105,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, child_relpath, depth_below_here, processor, pdb, - changelist_hash, diff_pristine, cancel_func, cancel_baton, iterpool)); @@ -1246,7 +1200,6 @@ handle_local_only(struct dir_baton_t *pb svn_relpath_join(pb->relpath, name, scratch_pool), repos_delete ? svn_depth_infinity : depth, eb->processor, pb->pdb, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, scratch_pool)); @@ -1257,7 +1210,6 @@ handle_local_only(struct dir_baton_t *pb svn_dirent_join(pb->local_abspath, name, scratch_pool), svn_relpath_join(pb->relpath, name, scratch_pool), eb->processor, pb->pdb, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, scratch_pool)); @@ -2032,7 +1984,14 @@ close_file(void *file_baton, const char *repos_file; apr_hash_t *repos_props; - if (!fb->skip && expected_md5_digest != NULL) + if (fb->skip) + { + svn_pool_destroy(fb->pool); /* destroys scratch_pool and fb */ + SVN_ERR(maybe_done(pb)); + return SVN_NO_ERROR; + } + + if (expected_md5_digest != NULL) { svn_checksum_t *expected_checksum; const svn_checksum_t *result_checksum; @@ -2087,11 +2046,7 @@ close_file(void *file_baton, } } - if (fb->skip) - { - /* Diff processor requested skipping information */ - } - else if (fb->repos_only) + if (fb->repos_only) { SVN_ERR(eb->processor->file_deleted(fb->relpath, fb->left_src, @@ -2271,6 +2226,7 @@ svn_wc__get_diff_editor(const svn_delta_ struct svn_wc__shim_fetch_baton_t *sfb; svn_delta_shim_callbacks_t *shim_callbacks = svn_delta_shim_callbacks_default(result_pool); + const svn_diff_tree_processor_t *diff_processor; SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath)); @@ -2278,12 +2234,28 @@ svn_wc__get_diff_editor(const svn_delta_ if (use_git_diff_format) show_copies_as_adds = TRUE; + SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor, + callbacks, callback_baton, TRUE, + result_pool, scratch_pool)); + + /* Apply changelist filtering to the output */ + if (changelist_filter && changelist_filter->nelts) + { + apr_hash_t *changelist_hash; + + SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, + result_pool)); + diff_processor = svn_wc__changelist_filter_tree_processor_create( + diff_processor, wc_ctx, anchor_abspath, + changelist_hash, result_pool); + } + SVN_ERR(make_edit_baton(&eb, wc_ctx->db, anchor_abspath, target, - callbacks, callback_baton, + diff_processor, depth, ignore_ancestry, show_copies_as_adds, - use_text_base, reverse_order, changelist_filter, + use_text_base, reverse_order, cancel_func, cancel_baton, result_pool)); @@ -2749,3 +2721,329 @@ svn_wc__wrap_diff_callbacks(const svn_di *diff_processor = processor; return SVN_NO_ERROR; } + +/* ===================================================================== + * A tree processor filter that filters by changelist membership + * ===================================================================== + * + * The current implementation queries the WC for the changelist of each + * file as it comes through, and sets the 'skip' flag for a non-matching + * file. + * + * (It doesn't set the 'skip' flag for a directory, as we need to receive + * the changed/added/deleted/closed call to know when it is closed, in + * order to preserve the strict open-close semantics for the wrapped tree + * processor.) + * + * It passes on the opening and closing of every directory, even if there + * are no file changes to be passed on inside that directory. + */ + +typedef struct filter_tree_baton_t +{ + const svn_diff_tree_processor_t *processor; + svn_wc_context_t *wc_ctx; + /* WC path of the root of the diff (where relpath = "") */ + const char *root_local_abspath; + /* Hash whose keys are const char * changelist names. */ + apr_hash_t *changelist_hash; +} filter_tree_baton_t; + +static svn_error_t * +filter_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children, + relpath, + left_source, right_source, + copyfrom_source, + parent_dir_baton, + fb->processor, + result_pool, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + NULL, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + NULL, + dir_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + const char *local_abspath + = svn_dirent_join(fb->root_local_abspath, relpath, scratch_pool); + + /* Skip if not a member of a given changelist */ + if (! svn_wc__changelist_match(fb->wc_ctx, local_abspath, + fb->changelist_hash, scratch_pool)) + { + *skip = TRUE; + return SVN_NO_ERROR; + } + + SVN_ERR(fb->processor->file_opened(new_file_baton, + skip, + relpath, + left_source, + right_source, + copyfrom_source, + dir_baton, + fb->processor, + result_pool, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_added(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + file_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_deleted(relpath, + left_source, + left_file, + left_props, + file_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_changed(relpath, + left_source, + right_source, + left_file, + right_file, + left_props, + right_props, + file_modified, + prop_changes, + file_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_closed(relpath, + left_source, + right_source, + file_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->node_absent(relpath, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +const svn_diff_tree_processor_t * +svn_wc__changelist_filter_tree_processor_create( + const svn_diff_tree_processor_t *processor, + svn_wc_context_t *wc_ctx, + const char *root_local_abspath, + apr_hash_t *changelist_hash, + apr_pool_t *result_pool) +{ + struct filter_tree_baton_t *fb; + svn_diff_tree_processor_t *filter; + + if (! changelist_hash) + return processor; + + fb = apr_pcalloc(result_pool, sizeof(*fb)); + fb->processor = processor; + fb->wc_ctx = wc_ctx; + fb->root_local_abspath = root_local_abspath; + fb->changelist_hash = changelist_hash; + + filter = svn_diff__tree_processor_create(fb, result_pool); + filter->dir_opened = filter_dir_opened; + filter->dir_added = filter_dir_added; + filter->dir_deleted = filter_dir_deleted; + filter->dir_changed = filter_dir_changed; + filter->dir_closed = filter_dir_closed; + + filter->file_opened = filter_file_opened; + filter->file_added = filter_file_added; + filter->file_deleted = filter_file_deleted; + filter->file_changed = filter_file_changed; + filter->file_closed = filter_file_closed; + + filter->node_absent = filter_node_absent; + + return filter; +} + Modified: subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_local.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_local.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_local.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/libsvn_wc/diff_local.c Sun Dec 14 11:52:14 2014 @@ -92,9 +92,6 @@ struct diff_baton /* Should this diff not compare copied files with their source? */ svn_boolean_t show_copies_as_adds; - /* Hash whose keys are const char * changelist names. */ - apr_hash_t *changelist_hash; - /* Cancel function/baton */ svn_cancel_func_t cancel_func; void *cancel_baton; @@ -252,11 +249,6 @@ diff_status_callback(void *baton, if (eb->cur && eb->cur->skip_children) return SVN_NO_ERROR; - if (eb->changelist_hash != NULL - && (!status->changelist - || ! svn_hash_gets(eb->changelist_hash, status->changelist))) - return SVN_NO_ERROR; /* Filtered via changelist */ - /* This code does about the same thing as the inner body of walk_local_nodes_diff() in diff_editor.c, except that it is already filtered by the status walker, doesn't have to @@ -361,7 +353,6 @@ diff_status_callback(void *baton, SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath, child_relpath, SVN_INVALID_REVNUM, - eb->changelist_hash, eb->processor, eb->cur ? eb->cur->baton @@ -405,7 +396,6 @@ diff_status_callback(void *baton, child_relpath, eb->processor, eb->cur ? eb->cur->baton : NULL, - eb->changelist_hash, FALSE, eb->cancel_func, eb->cancel_baton, @@ -415,7 +405,6 @@ diff_status_callback(void *baton, child_relpath, depth_below_here, eb->processor, eb->cur ? eb->cur->baton : NULL, - eb->changelist_hash, FALSE, eb->cancel_func, eb->cancel_baton, @@ -482,16 +471,24 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx, processor = svn_diff__tree_processor_copy_as_changed_create(processor, scratch_pool); + /* Apply changelist filtering to the output */ + if (changelist_filter && changelist_filter->nelts) + { + apr_hash_t *changelist_hash; + + SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, + scratch_pool)); + processor = svn_wc__changelist_filter_tree_processor_create( + processor, wc_ctx, local_abspath, + changelist_hash, scratch_pool); + } + eb.db = wc_ctx->db; eb.processor = processor; eb.ignore_ancestry = ignore_ancestry; eb.show_copies_as_adds = show_copies_as_adds; eb.pool = scratch_pool; - if (changelist_filter && changelist_filter->nelts) - SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter, - scratch_pool)); - if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry) get_all = TRUE; /* We need unmodified descendants of copies */ else Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/deleted-rev.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/deleted-rev.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/deleted-rev.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/deleted-rev.c Sun Dec 14 11:52:14 2014 @@ -56,6 +56,9 @@ dav_svn__get_deleted_rev_report(const da dav_error *derr = NULL; /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0, Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/file-revs.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/file-revs.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/file-revs.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/file-revs.c Sun Dec 14 11:52:14 2014 @@ -254,6 +254,9 @@ dav_svn__file_revs_report(const dav_reso arb.repos = resource->info->repos; /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); /* ### This is done on other places, but the document element is in this namespace, so is this necessary at all? */ Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-location-segments.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-location-segments.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-location-segments.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-location-segments.c Sun Dec 14 11:52:14 2014 @@ -123,6 +123,9 @@ dav_svn__get_location_segments_report(co struct location_segment_baton location_segment_baton; /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) { Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-locations.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-locations.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-locations.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/get-locations.c Sun Dec 14 11:52:14 2014 @@ -106,6 +106,9 @@ dav_svn__get_locations_report(const dav_ sizeof(svn_revnum_t)); /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) { Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/inherited-props.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/inherited-props.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/inherited-props.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/inherited-props.c Sun Dec 14 11:52:14 2014 @@ -63,6 +63,9 @@ dav_svn__get_inherited_props_report(cons apr_pool_t *iterpool; /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) { Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/log.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/log.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/log.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/log.c Sun Dec 14 11:52:14 2014 @@ -307,6 +307,9 @@ dav_svn__log_report(const dav_resource * = apr_array_make(resource->pool, 1, sizeof(const char *)); /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) { Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/mergeinfo.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/mergeinfo.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/reports/mergeinfo.c Sun Dec 14 11:52:14 2014 @@ -67,6 +67,9 @@ dav_svn__get_mergeinfo_report(const dav_ = apr_array_make(resource->pool, 0, sizeof(const char *)); /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) { Modified: subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/repos.c URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/repos.c?rev=1645441&r1=1645440&r2=1645441&view=diff ============================================================================== --- subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/repos.c (original) +++ subversion/branches/javahl-1.8-extensions/subversion/mod_dav_svn/repos.c Sun Dec 14 11:52:14 2014 @@ -508,6 +508,9 @@ parse_vtxnstub_uri(dav_resource_combined if (parse_txnstub_uri(comb, path, label, use_checked_in)) return TRUE; + if (!comb->priv.root.txn_name) + return TRUE; + comb->priv.root.vtxn_name = comb->priv.root.txn_name; comb->priv.root.txn_name = dav_svn__get_txn(comb->priv.repos, comb->priv.root.vtxn_name); @@ -576,6 +579,9 @@ parse_vtxnroot_uri(dav_resource_combined if (parse_txnroot_uri(comb, path, label, use_checked_in)) return TRUE; + if (!comb->priv.root.txn_name) + return TRUE; + comb->priv.root.vtxn_name = comb->priv.root.txn_name; comb->priv.root.txn_name = dav_svn__get_txn(comb->priv.repos, comb->priv.root.vtxn_name); @@ -921,6 +927,10 @@ prep_working(dav_resource_combined *comb point. */ if (txn_name == NULL) { + if (!comb->priv.root.activity_id) + return dav_svn__new_error(comb->res.pool, HTTP_BAD_REQUEST, 0, + "The request did not specify an activity ID"); + txn_name = dav_svn__get_txn(comb->priv.repos, comb->priv.root.activity_id); if (txn_name == NULL) @@ -1031,8 +1041,13 @@ prep_working(dav_resource_combined *comb static dav_error * prep_activity(dav_resource_combined *comb) { - const char *txn_name = dav_svn__get_txn(comb->priv.repos, - comb->priv.root.activity_id); + const char *txn_name; + + if (!comb->priv.root.activity_id) + return dav_svn__new_error(comb->res.pool, HTTP_BAD_REQUEST, 0, + "The request did not specify an activity ID"); + + txn_name = dav_svn__get_txn(comb->priv.repos, comb->priv.root.activity_id); comb->priv.root.txn_name = txn_name; comb->res.exists = txn_name != NULL; @@ -4144,7 +4159,9 @@ typedef struct walker_ctx_t { static dav_error * -do_walk(walker_ctx_t *ctx, int depth) +do_walk(walker_ctx_t *ctx, + int depth, + apr_pool_t *scratch_pool) { const dav_walk_params *params = ctx->params; int isdir = ctx->res.collection; @@ -4217,19 +4234,19 @@ do_walk(walker_ctx_t *ctx, int depth) svn_log__get_dir(ctx->info.repos_path, ctx->info.root.rev, TRUE, FALSE, SVN_DIRENT_ALL, - params->pool)); + scratch_pool)); /* fetch this collection's children */ serr = svn_fs_dir_entries(&children, ctx->info.root.root, - ctx->info.repos_path, params->pool); + ctx->info.repos_path, scratch_pool); if (serr != NULL) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not fetch collection members", params->pool); /* iterate over the children in this collection */ - iterpool = svn_pool_create(params->pool); - for (hi = apr_hash_first(params->pool, children); hi; hi = apr_hash_next(hi)) + iterpool = svn_pool_create(scratch_pool); + for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi)) { const void *key; apr_ssize_t klen; @@ -4282,7 +4299,7 @@ do_walk(walker_ctx_t *ctx, int depth) ctx->res.uri = ctx->uri->data; /* recurse on this collection */ - err = do_walk(ctx, depth - 1); + err = do_walk(ctx, depth - 1, iterpool); if (err != NULL) return err; @@ -4364,7 +4381,7 @@ walk(const dav_walk_params *params, int /* ### is the root already/always open? need to verify */ /* always return the error, and any/all multistatus responses */ - err = do_walk(&ctx, depth); + err = do_walk(&ctx, depth, params->pool); *response = ctx.wres.response; return err;
