From commits-return-50547-archive-asf-public=cust-asf.ponee.io@subversion.apache.org Mon Jul 8 15:19:12 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [207.244.88.153]) by mx-eu-01.ponee.io (Postfix) with SMTP id DDF85180677 for ; Mon, 8 Jul 2019 17:19:11 +0200 (CEST) Received: (qmail 83219 invoked by uid 500); 8 Jul 2019 15:19:10 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 83070 invoked by uid 99); 8 Jul 2019 15:19:10 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 08 Jul 2019 15:19:10 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 494323A37DC for ; Mon, 8 Jul 2019 15:19:08 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1862754 [7/9] - in /subversion/branches/swig-py3: ./ build/ac-macros/ build/generator/ doc/ doc/programmer/ notes/ notes/shelving/ subversion/bindings/cxx/ subversion/bindings/cxxhl/ subversion/bindings/javahl/native/ subversion/bindings/j... Date: Mon, 08 Jul 2019 15:19:05 -0000 To: commits@subversion.apache.org From: futatuki@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20190708151908.494323A37DC@svn01-us-west.apache.org> Modified: subversion/branches/swig-py3/subversion/libsvn_repos/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/deprecated.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_repos/deprecated.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_repos/deprecated.c Mon Jul 8 15:19:03 2019 @@ -1273,6 +1273,21 @@ svn_repos_fs_begin_txn_for_update(svn_fs /*** From authz.c ***/ svn_error_t * +svn_repos_authz_read3(svn_authz_t **authz_p, + const char *path, + const char *groups_path, + svn_boolean_t must_exist, + svn_repos_t *repos_hint, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace(svn_repos_authz_read4(authz_p, path, groups_path, + must_exist, repos_hint, + NULL, NULL, result_pool, + scratch_pool)); +} + +svn_error_t * svn_repos_authz_read2(svn_authz_t **authz_p, const char *path, const char *groups_path, @@ -1300,3 +1315,17 @@ svn_repos_authz_read(svn_authz_t **authz return svn_error_trace(svn_repos_authz_read2(authz_p, file, NULL, must_exist, pool)); } + +svn_error_t * +svn_repos_authz_parse(svn_authz_t **authz_p, + svn_stream_t *stream, + svn_stream_t *groups_stream, + apr_pool_t *pool) +{ + apr_pool_t *scratch_pool = svn_pool_create(pool); + svn_error_t *err = svn_repos_authz_parse2(authz_p, stream, groups_stream, + NULL, NULL, pool, scratch_pool); + svn_pool_destroy(scratch_pool); + + return svn_error_trace(err); +} Modified: subversion/branches/swig-py3/subversion/libsvn_repos/dump.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/dump.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_repos/dump.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_repos/dump.c Mon Jul 8 15:19:03 2019 @@ -44,6 +44,7 @@ #include "private/svn_sorts_private.h" #include "private/svn_utf_private.h" #include "private/svn_cache.h" +#include "private/svn_fspath.h" #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r)) @@ -1996,6 +1997,11 @@ dump_filter_authz_func(svn_boolean_t *al { dump_filter_baton_t *b = baton; + /* For some nodes (e.g. files under copied directory) PATH may be + * non-canonical (missing leading '/'). Canonicalize PATH before + * passing it to FILTER_FUNC. */ + path = svn_fspath__canonicalize(path, pool); + return svn_error_trace(b->filter_func(allowed, root, path, b->filter_baton, pool)); } Modified: subversion/branches/swig-py3/subversion/libsvn_repos/replay.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/replay.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_repos/replay.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_repos/replay.c Mon Jul 8 15:19:03 2019 @@ -126,9 +126,6 @@ struct copy_info struct path_driver_cb_baton { - const svn_delta_editor_t *editor; - void *edit_baton; - /* The root of the revision we're replaying. */ svn_fs_root_t *root; @@ -454,14 +451,14 @@ fill_copyfrom(svn_fs_root_t **copyfrom_r static svn_error_t * path_driver_cb_func(void **dir_baton, + const svn_delta_editor_t *editor, + void *edit_baton, void *parent_baton, void *callback_baton, const char *edit_path, apr_pool_t *pool) { struct path_driver_cb_baton *cb = callback_baton; - const svn_delta_editor_t *editor = cb->editor; - void *edit_baton = cb->edit_baton; svn_fs_root_t *root = cb->root; svn_fs_path_change3_t *change; svn_boolean_t do_add = FALSE, do_delete = FALSE; @@ -957,8 +954,6 @@ svn_repos_replay2(svn_fs_root_t *root, low_water_mark = 0; /* Initialize our callback baton. */ - cb_baton.editor = editor; - cb_baton.edit_baton = edit_baton; cb_baton.root = root; cb_baton.changed_paths = changed_paths; cb_baton.authz_read_func = authz_read_func; @@ -989,7 +984,7 @@ svn_repos_replay2(svn_fs_root_t *root, } /* Call the path-based editor driver. */ - return svn_delta_path_driver2(editor, edit_baton, + return svn_delta_path_driver3(editor, edit_baton, paths, TRUE, path_driver_cb_func, &cb_baton, pool); #else Modified: subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c Mon Jul 8 15:19:03 2019 @@ -37,6 +37,7 @@ #include "svn_ctype.h" #include "dirent_uri.h" +#include "private/svn_dirent_uri_private.h" #include "private/svn_fspath.h" #include "private/svn_cert.h" @@ -934,14 +935,18 @@ svn_dirent_local_style(const char *diren return dirent; } -const char * -svn_relpath__internal_style(const char *relpath, - apr_pool_t *pool) +svn_error_t * +svn_relpath__make_internal(const char **internal_style_relpath, + const char *relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - return svn_relpath_canonicalize(internal_style(relpath, pool), pool); + return svn_error_trace( + svn_relpath_canonicalize_safe(internal_style_relpath, NULL, + internal_style(relpath, scratch_pool), + result_pool, scratch_pool)); } - /* We decided against using apr_filepath_root here because of the negative performance impact (creating a pool and converting strings ). */ svn_boolean_t Modified: subversion/branches/swig-py3/subversion/libsvn_subr/error.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/error.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/error.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/error.c Mon Jul 8 15:19:03 2019 @@ -146,6 +146,7 @@ svn_error__locate(const char *file, long /* Cleanup function for errors. svn_error_clear () removes this so errors that are properly handled *don't* hit this code. */ +#ifdef SVN_DEBUG static apr_status_t err_abort(void *data) { svn_error_t *err = data; /* For easy viewing in a debugger */ @@ -155,6 +156,7 @@ static apr_status_t err_abort(void *data abort(); return APR_SUCCESS; } +#endif static svn_error_t * Modified: subversion/branches/swig-py3/subversion/libsvn_subr/io.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/io.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/io.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/io.c Mon Jul 8 15:19:03 2019 @@ -155,8 +155,14 @@ typedef struct _FILE_DISPOSITION_INFO { BOOL DeleteFile; } FILE_DISPOSITION_INFO, *PFILE_DISPOSITION_INFO; +typedef struct _FILE_ATTRIBUTE_TAG_INFO { + DWORD FileAttributes; + DWORD ReparseTag; +} FILE_ATTRIBUTE_TAG_INFO, *PFILE_ATTRIBUTE_TAG_INFO; + #define FileRenameInfo 3 #define FileDispositionInfo 4 +#define FileAttributeTagInfo 9 #endif /* WIN32 < Vista */ /* One-time initialization of the late bound Windows API functions. */ @@ -169,19 +175,30 @@ typedef DWORD (WINAPI *GETFINALPATHNAMEB DWORD cchFilePath, DWORD dwFlags); +typedef BOOL (WINAPI *GetFileInformationByHandleEx_t)(HANDLE hFile, + int FileInformationClass, + LPVOID lpFileInformation, + DWORD dwBufferSize); + typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile, int FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize); static GETFINALPATHNAMEBYHANDLE get_final_path_name_by_handle_proc = NULL; +static GetFileInformationByHandleEx_t get_file_information_by_handle_ex_proc = NULL; static SetFileInformationByHandle_t set_file_information_by_handle_proc = NULL; -/* Forward declaration. */ +/* Forward declarations. */ static svn_error_t * io_win_read_link(svn_string_t **dest, const char *path, apr_pool_t *pool); +static svn_error_t * io_win_check_path(svn_node_kind_t *kind_p, + svn_boolean_t *is_symlink_p, + const char *path, + apr_pool_t *pool); + #endif /* Forward declaration */ @@ -342,13 +359,7 @@ io_check_path(const char *path, /* Not using svn_io_stat() here because we want to check the apr_err return explicitly. */ SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); -#ifdef WIN32 - /* on Windows, svn does not handle reparse points or hard links. - So ignore the 'resolve_symlinks' flag. */ - flags = APR_FINFO_MIN; -#else flags = resolve_symlinks ? APR_FINFO_MIN : (APR_FINFO_MIN | APR_FINFO_LINK); -#endif apr_err = apr_stat(&finfo, path_apr, flags, pool); if (APR_STATUS_IS_ENOENT(apr_err)) @@ -410,8 +421,12 @@ svn_io_check_resolved_path(const char *p svn_node_kind_t *kind, apr_pool_t *pool) { +#if WIN32 + return io_win_check_path(kind, NULL, path, pool); +#else svn_boolean_t ignored; return io_check_path(path, TRUE, &ignored, kind, pool); +#endif } svn_error_t * @@ -419,8 +434,19 @@ svn_io_check_path(const char *path, svn_node_kind_t *kind, apr_pool_t *pool) { +#if WIN32 + svn_boolean_t is_symlink; + + SVN_ERR(io_win_check_path(kind, &is_symlink, path, pool)); + + if (is_symlink) + *kind = svn_node_file; + + return SVN_NO_ERROR; +#else svn_boolean_t ignored; return io_check_path(path, FALSE, &ignored, kind, pool); +#endif } svn_error_t * @@ -429,7 +455,23 @@ svn_io_check_special_path(const char *pa svn_boolean_t *is_special, apr_pool_t *pool) { +#ifdef WIN32 + svn_boolean_t is_symlink; + + SVN_ERR(io_win_check_path(kind, &is_symlink, path, pool)); + + if (is_symlink) + { + *is_special = TRUE; + *kind = svn_node_file; + } + else + *is_special = FALSE; + + return SVN_NO_ERROR; +#else return io_check_path(path, FALSE, is_special, kind, pool); +#endif } struct temp_file_cleanup_s @@ -1622,13 +1664,14 @@ merge_default_file_perms(apr_file_t *fd, that attempts to honor the users umask when dealing with permission changes. It is a no-op when invoked on a symlink. */ static svn_error_t * -io_set_file_perms(const char *path, - svn_boolean_t change_readwrite, - svn_boolean_t enable_write, - svn_boolean_t change_executable, - svn_boolean_t executable, - svn_boolean_t ignore_enoent, - apr_pool_t *pool) +io_set_perms(const char *path, + svn_boolean_t is_file, + svn_boolean_t change_readwrite, + svn_boolean_t enable_write, + svn_boolean_t change_executable, + svn_boolean_t executable, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) { apr_status_t status; const char *path_apr; @@ -1648,9 +1691,16 @@ io_set_file_perms(const char *path, || SVN__APR_STATUS_IS_ENOTDIR(status))) return SVN_NO_ERROR; else if (status != APR_ENOTIMPL) - return svn_error_wrap_apr(status, - _("Can't change perms of file '%s'"), - svn_dirent_local_style(path, pool)); + { + if (is_file) + return svn_error_wrap_apr(status, + _("Can't change perms of file '%s'"), + svn_dirent_local_style(path, pool)); + else + return svn_error_wrap_apr(status, + _("Can't change perms of directory '%s'"), + svn_dirent_local_style(path, pool)); + } return SVN_NO_ERROR; } @@ -1750,10 +1800,50 @@ io_set_file_perms(const char *path, status = apr_file_attrs_set(path_apr, attrs, attrs_values, pool); } - return svn_error_wrap_apr(status, - _("Can't change perms of file '%s'"), - svn_dirent_local_style(path, pool)); + if (is_file) + { + return svn_error_wrap_apr(status, + _("Can't change perms of file '%s'"), + svn_dirent_local_style(path, pool)); + } + else + { + return svn_error_wrap_apr(status, + _("Can't change perms of directory '%s'"), + svn_dirent_local_style(path, pool)); + } +} + +static svn_error_t * +io_set_file_perms(const char *path, + svn_boolean_t change_readwrite, + svn_boolean_t enable_write, + svn_boolean_t change_executable, + svn_boolean_t executable, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + return svn_error_trace(io_set_perms(path, TRUE, + change_readwrite, enable_write, + change_executable, executable, + ignore_enoent, pool)); +} + +static svn_error_t * +io_set_dir_perms(const char *path, + svn_boolean_t change_readwrite, + svn_boolean_t enable_write, + svn_boolean_t change_executable, + svn_boolean_t executable, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + return svn_error_trace(io_set_perms(path, FALSE, + change_readwrite, enable_write, + change_executable, executable, + ignore_enoent, pool)); } + #endif /* !WIN32 && !__OS2__ */ #ifdef WIN32 @@ -1902,6 +1992,9 @@ static svn_error_t *win_init_dynamic_imp get_final_path_name_by_handle_proc = (GETFINALPATHNAMEBYHANDLE) GetProcAddress(kernel32, "GetFinalPathNameByHandleW"); + get_file_information_by_handle_ex_proc = (GetFileInformationByHandleEx_t) + GetProcAddress(kernel32, "GetFileInformationByHandleEx"); + set_file_information_by_handle_proc = (SetFileInformationByHandle_t) GetProcAddress(kernel32, "SetFileInformationByHandle"); } @@ -1978,6 +2071,33 @@ static svn_error_t * io_win_read_link(sv } } +/* Wrapper around Windows API function GetFileInformationByHandleEx() that + * returns APR status instead of boolean flag. */ +static apr_status_t +win32_get_file_information_by_handle(HANDLE hFile, + int FileInformationClass, + LPVOID lpFileInformation, + DWORD dwBufferSize) +{ + svn_error_clear(svn_atomic__init_once(&win_dynamic_imports_state, + win_init_dynamic_imports, + NULL, NULL)); + + if (!get_file_information_by_handle_ex_proc) + { + return SVN_ERR_UNSUPPORTED_FEATURE; + } + + if (!get_file_information_by_handle_ex_proc(hFile, FileInformationClass, + lpFileInformation, + dwBufferSize)) + { + return apr_get_os_error(); + } + + return APR_SUCCESS; +} + /* Wrapper around Windows API function SetFileInformationByHandle() that * returns APR status instead of boolean flag. */ static apr_status_t @@ -2005,6 +2125,105 @@ win32_set_file_information_by_handle(HAN return APR_SUCCESS; } +/* Fast Win32-specific helper for svn_io_check_path() and related functions + * that only requires a single GetFileAttributes() call in most cases. + */ +static svn_error_t * io_win_check_path(svn_node_kind_t *kind_p, + svn_boolean_t *is_symlink_p, + const char *path, + apr_pool_t *pool) +{ + DWORD attrs; + const WCHAR *wpath; + apr_status_t status; + + if (path[0] == '\0') + path = "."; + + SVN_ERR(svn_io__utf8_to_unicode_longpath(&wpath, path, pool)); + + attrs = GetFileAttributesW(wpath); + if (attrs == INVALID_FILE_ATTRIBUTES) + { + status = apr_get_os_error(); + if (APR_STATUS_IS_ENOENT(status) || SVN__APR_STATUS_IS_ENOTDIR(status)) + { + *kind_p = svn_node_none; + if (is_symlink_p) + *is_symlink_p = FALSE; + return SVN_NO_ERROR; + } + else + { + return svn_error_wrap_apr(status, _("Can't stat '%s'"), + svn_dirent_local_style(path, pool)); + } + } + + if (attrs & FILE_ATTRIBUTE_DIRECTORY) + *kind_p = svn_node_dir; + else + *kind_p = svn_node_file; + + /* If this is a reparse point, and if we've been asked to check whether + we are dealing with a symlink, then open the file and check that. + + Otherwise, it's either definitely not a symlink or the caller + doesn't care about this distinction. + */ + if (is_symlink_p && (attrs & FILE_ATTRIBUTE_REPARSE_POINT)) + { + const WCHAR *wfname; + HANDLE hFile; + FILE_ATTRIBUTE_TAG_INFO taginfo = { 0 }; + + SVN_ERR(svn_io__utf8_to_unicode_longpath(&wfname, path, pool)); + + hFile = CreateFileW(wfname, FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + status = apr_get_os_error(); + if (APR_STATUS_IS_ENOENT(status) || SVN__APR_STATUS_IS_ENOTDIR(status)) + { + *kind_p = svn_node_none; + *is_symlink_p = FALSE; + return SVN_NO_ERROR; + } + else + { + return svn_error_wrap_apr(status, _("Can't stat '%s'"), + svn_dirent_local_style(path, pool)); + } + } + + status = win32_get_file_information_by_handle(hFile, FileAttributeTagInfo, + &taginfo, sizeof(taginfo)); + CloseHandle(hFile); + + if (status) + return svn_error_wrap_apr(status, _("Can't stat '%s'"), + svn_dirent_local_style(path, pool)); + + /* The surrogate bit in the reparse tag specifies if "the file or directory + represents another named entity in the system" which is used to determine + if this reparse point behaves like a symlink. + + https://docs.microsoft.com/en-us/windows/desktop/fileio/reparse-point-tags + */ + *is_symlink_p = IsReparseTagNameSurrogate(taginfo.ReparseTag); + } + else if (is_symlink_p) + { + *is_symlink_p = FALSE; + } + + return SVN_NO_ERROR; +} + svn_error_t * svn_io__win_delete_file_on_close(apr_file_t *file, const char *path, @@ -2115,6 +2334,55 @@ svn_io_set_file_read_write_carefully(con return svn_io_set_file_read_only(path, ignore_enoent, pool); } +#if defined(WIN32) || defined(__OS2__) +/* Helper for svn_io_set_file_read_* */ +static svn_error_t * +io_set_readonly_flag(const char *path_apr, /* file-system path */ + const char *path, /* UTF-8 path */ + svn_boolean_t set_flag, + svn_boolean_t is_file, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + apr_status_t status; + + status = apr_file_attrs_set(path_apr, + (set_flag ? APR_FILE_ATTR_READONLY : 0), + APR_FILE_ATTR_READONLY, + pool); + + if (status && status != APR_ENOTIMPL) + if (!(ignore_enoent && (APR_STATUS_IS_ENOENT(status) + || SVN__APR_STATUS_IS_ENOTDIR(status)))) + { + if (is_file) + { + if (set_flag) + return svn_error_wrap_apr(status, + _("Can't set file '%s' read-only"), + svn_dirent_local_style(path, pool)); + else + return svn_error_wrap_apr(status, + _("Can't set file '%s' read-write"), + svn_dirent_local_style(path, pool)); + } + else + { + if (set_flag) + return svn_error_wrap_apr(status, + _("Can't set directory '%s' read-only"), + svn_dirent_local_style(path, pool)); + else + return svn_error_wrap_apr(status, + _("Can't set directory '%s' read-write"), + svn_dirent_local_style(path, pool)); + } + } + return SVN_NO_ERROR; +} +#endif + + svn_error_t * svn_io_set_file_read_only(const char *path, svn_boolean_t ignore_enoent, @@ -2126,24 +2394,11 @@ svn_io_set_file_read_only(const char *pa return io_set_file_perms(path, TRUE, FALSE, FALSE, FALSE, ignore_enoent, pool); #else - apr_status_t status; const char *path_apr; SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); - - status = apr_file_attrs_set(path_apr, - APR_FILE_ATTR_READONLY, - APR_FILE_ATTR_READONLY, - pool); - - if (status && status != APR_ENOTIMPL) - if (!(ignore_enoent && (APR_STATUS_IS_ENOENT(status) - || SVN__APR_STATUS_IS_ENOTDIR(status)))) - return svn_error_wrap_apr(status, - _("Can't set file '%s' read-only"), - svn_dirent_local_style(path, pool)); - - return SVN_NO_ERROR; + return io_set_readonly_flag(path_apr, path, + TRUE, TRUE, ignore_enoent, pool); #endif } @@ -2159,23 +2414,11 @@ svn_io_set_file_read_write(const char *p return io_set_file_perms(path, TRUE, TRUE, FALSE, FALSE, ignore_enoent, pool); #else - apr_status_t status; const char *path_apr; SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); - - status = apr_file_attrs_set(path_apr, - 0, - APR_FILE_ATTR_READONLY, - pool); - - if (status && status != APR_ENOTIMPL) - if (!ignore_enoent || !APR_STATUS_IS_ENOENT(status)) - return svn_error_wrap_apr(status, - _("Can't set file '%s' read-write"), - svn_dirent_local_style(path, pool)); - - return SVN_NO_ERROR; + return io_set_readonly_flag(path_apr, path, + FALSE, TRUE, ignore_enoent, pool); #endif } @@ -2761,6 +3004,12 @@ svn_io_remove_dir2(const char *path, svn return svn_error_trace(err); } + /* On Unix, nothing can be removed from a non-writable directory. */ +#if !defined(WIN32) && !defined(__OS2__) + SVN_ERR(io_set_dir_perms(path, TRUE, TRUE, FALSE, FALSE, + ignore_enoent, pool)); +#endif + for (hi = apr_hash_first(subpool, dirents); hi; hi = apr_hash_next(hi)) { const char *name = apr_hash_this_key(hi); @@ -4499,8 +4748,17 @@ svn_io_dir_remove_nonrecursive(const cha { svn_boolean_t retry = TRUE; + if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status)) + { + /* Make the destination directory writable because Windows + forbids deleting read-only items. */ + SVN_ERR(io_set_readonly_flag(dirname_apr, dirname, + FALSE, FALSE, TRUE, pool)); + status = apr_dir_remove(dirname_apr, pool); + } + if (status == APR_FROM_OS_ERROR(ERROR_DIR_NOT_EMPTY)) - { + { apr_status_t empty_status = dir_is_empty(dirname_apr, pool); if (APR_STATUS_IS_ENOTEMPTY(empty_status)) Modified: subversion/branches/swig-py3/subversion/libsvn_subr/pool.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/pool.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/pool.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/pool.c Mon Jul 8 15:19:03 2019 @@ -133,7 +133,7 @@ svn_pool_create_allocator(svn_boolean_t #endif /* By default, allocators are *not* thread-safe. We must provide a mutex - * if we want thread-safety for that mutex. */ + * if we want thread-safety for that pool. */ #if APR_HAS_THREADS if (thread_safe) Modified: subversion/branches/swig-py3/subversion/libsvn_subr/version.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/version.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/version.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/version.c Mon Jul 8 15:19:03 2019 @@ -143,7 +143,7 @@ svn_version_extended(svn_boolean_t verbo info->build_time = __TIME__; info->build_host = SVN_BUILD_HOST; info->copyright = apr_pstrdup - (pool, _("Copyright (C) 2018 The Apache Software Foundation.\n" + (pool, _("Copyright (C) 2019 The Apache Software Foundation.\n" "This software consists of contributions made by many people;\n" "see the NOTICE file for more information.\n" "Subversion is open source software, see " Modified: subversion/branches/swig-py3/subversion/libsvn_wc/node.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/node.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/node.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/node.c Mon Jul 8 15:19:03 2019 @@ -1140,3 +1140,17 @@ svn_wc__find_working_nodes_with_basename abspaths, wc_ctx->db, wri_abspath, basename, kind, result_pool, scratch_pool)); } + +svn_error_t * +svn_wc__find_copies_of_repos_path(apr_array_header_t **abspaths, + const char *wri_abspath, + const char *repos_relpath, + svn_node_kind_t kind, + svn_wc_context_t *wc_ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace(svn_wc__db_find_copies_of_repos_path( + abspaths, wc_ctx->db, wri_abspath, repos_relpath, + kind, result_pool, scratch_pool)); +} Modified: subversion/branches/swig-py3/subversion/libsvn_wc/revert.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/revert.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/revert.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/revert.c Mon Jul 8 15:19:03 2019 @@ -62,6 +62,18 @@ the addition of all the directory's children. Again, svn_wc_remove_from_revision_control() should do the trick. + - For a copy, we remove the item from disk as well. The thinking here + is that Subversion is responsible for the existence of the item: it + must have been created by something like 'svn copy' or 'svn merge'. + + - For a plain add, removing the file or directory from disk is optional. + The user's idea of Subversion's involvement could be either that + Subversion was just responsible for adding an existing item to version + control, as with 'svn add', and so should not be responsible for + deleting it from disk; or that Subversion is responsible for the + existence of the item, e.g. if created by 'svn patch' or svn mkdir'. + It depends on the use case. + Deletes - Restore properties to their unmodified state. Modified: subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c Mon Jul 8 15:19:03 2019 @@ -1458,7 +1458,7 @@ check_tree_conflict(svn_skel_t **pconfli * Therefore, we need to start a separate crawl here. */ SVN_ERR(svn_wc__node_has_local_mods(&modified, NULL, - eb->db, local_abspath, FALSE, + eb->db, local_abspath, TRUE, eb->cancel_func, eb->cancel_baton, scratch_pool)); Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql Mon Jul 8 15:19:03 2019 @@ -1796,6 +1796,17 @@ WHERE wc_id = ?1 SELECT 1 FROM sqlite_master WHERE name='sqlite_stat1' AND type='table' LIMIT 1 +-- STMT_SELECT_COPIES_OF_REPOS_RELPATH +SELECT local_relpath +FROM nodes n +WHERE wc_id = ?1 AND repos_path = ?2 AND kind = ?3 + AND presence = MAP_NORMAL + AND op_depth = (SELECT MAX(op_depth) + FROM NODES w + WHERE w.wc_id = ?1 + AND w.local_relpath = n.local_relpath) +ORDER BY local_relpath ASC + /* ------------------------------------------------------------------------- */ /* Grab all the statements related to the schema. */ Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c Mon Jul 8 15:19:03 2019 @@ -16663,3 +16663,47 @@ svn_wc__db_find_working_nodes_with_basen return svn_error_trace(svn_sqlite__reset(stmt)); } + +svn_error_t * +svn_wc__db_find_copies_of_repos_path(apr_array_header_t **local_abspaths, + svn_wc__db_t *db, + const char *wri_abspath, + const char *repos_relpath, + svn_node_kind_t kind, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *wri_relpath; + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &wri_relpath, db, + wri_abspath, scratch_pool, + scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_COPIES_OF_REPOS_RELPATH)); + SVN_ERR(svn_sqlite__bindf(stmt, "ist", wcroot->wc_id, repos_relpath, + kind_map, kind)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + *local_abspaths = apr_array_make(result_pool, 1, sizeof(const char *)); + + while (have_row) + { + const char *local_relpath; + const char *local_abspath; + + local_relpath = svn_sqlite__column_text(stmt, 0, NULL); + local_abspath = svn_dirent_join(wcroot->abspath, local_relpath, + result_pool); + APR_ARRAY_PUSH(*local_abspaths, const char *) = local_abspath; + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + + return svn_error_trace(svn_sqlite__reset(stmt)); +} Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h Mon Jul 8 15:19:03 2019 @@ -3520,6 +3520,24 @@ svn_wc__db_find_working_nodes_with_basen svn_node_kind_t kind, apr_pool_t *result_pool, apr_pool_t *scratch_pool); + +/* Return an array of const char * elements, which represent local absolute + * paths for nodes, within the working copy indicated by WRI_ABSPATH, which + * are copies of REPOS_RELPATH and have node kind KIND. + * If no such nodes exist, return an empty array. + * + * This function returns only paths to nodes which are present in the highest + * layer of the WC. In other words, paths to deleted and/or excluded nodes are + * never returned. + */ +svn_error_t * +svn_wc__db_find_copies_of_repos_path(apr_array_header_t **local_abspaths, + svn_wc__db_t *db, + const char *wri_abspath, + const char *repos_relpath, + svn_node_kind_t kind, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* @} */ typedef svn_error_t * (*svn_wc__db_verify_cb_t)(void *baton, Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc_db_update_move.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc_db_update_move.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc_db_update_move.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc_db_update_move.c Mon Jul 8 15:19:03 2019 @@ -2175,11 +2175,12 @@ suitable_for_move(svn_wc__db_wcroot_t *w while (have_row) { svn_revnum_t node_revision = svn_sqlite__column_revnum(stmt, 2); - const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); + const char *child_relpath; const char *relpath; svn_pool_clear(iterpool); + child_relpath = svn_sqlite__column_text(stmt, 0, iterpool); relpath = svn_relpath_skip_ancestor(local_relpath, child_relpath); relpath = svn_relpath_join(repos_relpath, relpath, iterpool); Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wcroot_anchor.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wcroot_anchor.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wcroot_anchor.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wcroot_anchor.c Mon Jul 8 15:19:03 2019 @@ -183,21 +183,20 @@ svn_wc__get_wcroot(const char **wcroot_a svn_error_t * -svn_wc__get_shelves_dir(char **dir, - svn_wc_context_t *wc_ctx, - const char *local_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_wc__get_experimental_dir(char **dir, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { const char *wcroot_abspath; SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, wc_ctx, local_abspath, scratch_pool, scratch_pool)); *dir = svn_dirent_join(wcroot_abspath, - SVN_WC_ADM_DIR_NAME "/" SVN_WC__ADM_EXPERIMENTAL "/" - "shelves/v2", + SVN_WC_ADM_DIR_NAME "/" SVN_WC__ADM_EXPERIMENTAL, result_pool); - + /* Ensure the directory exists. (Other versions of svn don't create it.) */ SVN_ERR(svn_io_make_dir_recursively(*dir, scratch_pool)); Modified: subversion/branches/swig-py3/subversion/mod_authz_svn/mod_authz_svn.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/mod_authz_svn/mod_authz_svn.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/mod_authz_svn/mod_authz_svn.c (original) +++ subversion/branches/swig-py3/subversion/mod_authz_svn/mod_authz_svn.c Mon Jul 8 15:19:03 2019 @@ -327,16 +327,17 @@ log_access_verdict(LOG_ARGS_SIGNATURE, } } -/* Log a message indiciating the ERR encountered during the request R. +/* Log a message at LOG_LEVEL indiciating the ERR encountered during + * the request R. * LOG_ARGS_SIGNATURE expands as in log_access_verdict() above. * PREFIX is inserted at the start of the message. The rest of the * message is generated by combining the message for each error in the * chain of ERR, excluding for trace errors. ERR will be cleared * when finished. */ static void -log_svn_error(LOG_ARGS_SIGNATURE, - request_rec *r, const char *prefix, - svn_error_t *err, apr_pool_t *scratch_pool) +log_svn_message(LOG_ARGS_SIGNATURE, int log_level, + request_rec *r, const char *prefix, + svn_error_t *err, apr_pool_t *scratch_pool) { svn_error_t *err_pos = svn_error_purge_tracing(err); svn_stringbuf_t *buff = svn_stringbuf_create(prefix, scratch_pool); @@ -360,7 +361,7 @@ log_svn_error(LOG_ARGS_SIGNATURE, err_pos = err_pos->child; } - ap_log_rerror(LOG_ARGS_CASCADE, APLOG_ERR, + ap_log_rerror(LOG_ARGS_CASCADE, log_level, /* If it is an error code that APR can make sense of, then show it, otherwise, pass zero to avoid putting "APR does not understand this error code" in the error log. */ @@ -372,6 +373,40 @@ log_svn_error(LOG_ARGS_SIGNATURE, svn_error_clear(err); } +/* Log the error error ERR encountered during the request R. + * LOG_ARGS_SIGNATURE expands as in log_access_verdict() above. + * PREFIX is inserted at the start of the message. The rest of the + * message is generated by combining the message for each error in the + * chain of ERR, excluding for trace errors. ERR will be cleared + * when finished. */ +static APR_INLINE void +log_svn_error(LOG_ARGS_SIGNATURE, + request_rec *r, const char *prefix, + svn_error_t *err, apr_pool_t *scratch_pool) +{ + log_svn_message(LOG_ARGS_CASCADE, APLOG_ERR, + r, prefix, err, scratch_pool); +} + +/* Baton for log_authz_warning. */ +typedef struct authz_warning_baton_t +{ + request_rec *r; + const char *prefix; +} authz_warning_baton_t; + +/* Handle an authz parser warning. ERR will *not* be cleared.*/ +static APR_INLINE void +log_authz_warning(void *baton, + const svn_error_t *err, + apr_pool_t *scratch_pool) +{ + const authz_warning_baton_t *const warning_baton = baton; + log_svn_message(APLOG_MARK, APLOG_WARNING, + warning_baton->r, warning_baton->prefix, + svn_error_dup(err), scratch_pool); +} + /* Resolve *PATH into an absolute canonical URL iff *PATH is a repos-relative * URL. If *REPOS_URL is NULL convert REPOS_PATH into a file URL stored * in *REPOS_URL, if *REPOS_URL is not null REPOS_PATH is ignored. The @@ -472,8 +507,13 @@ get_access_conf(request_rec *r, authz_sv access_conf = user_data; if (access_conf == NULL) { - svn_err = svn_repos_authz_read3(&access_conf, access_file, + authz_warning_baton_t warning_baton; + warning_baton.r = r; + warning_baton.prefix = "mod_authz_svn: warning:"; + + svn_err = svn_repos_authz_read4(&access_conf, access_file, groups_file, TRUE, NULL, + log_authz_warning, &warning_baton, r->connection->pool, scratch_pool); Modified: subversion/branches/swig-py3/subversion/mod_dav_svn/reports/list.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/mod_dav_svn/reports/list.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/mod_dav_svn/reports/list.c (original) +++ subversion/branches/swig-py3/subversion/mod_dav_svn/reports/list.c Mon Jul 8 15:19:03 2019 @@ -201,7 +201,7 @@ dav_svn__list_report(const dav_resource dav_svn__authz_read_baton arb; const dav_svn_repos *repos = resource->info->repos; int ns; - const char *full_path; + const char *full_path = NULL; svn_boolean_t path_info_only; svn_fs_root_t *root; svn_depth_t depth = svn_depth_unknown; @@ -280,6 +280,12 @@ dav_svn__list_report(const dav_resource /* else unknown element; skip it */ } + if (! full_path) + { + return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0, 0, + "Request was missing the path argument"); + } + /* Build authz read baton */ arb.r = resource->info->r; arb.repos = resource->info->repos; Modified: subversion/branches/swig-py3/subversion/mod_dav_svn/repos.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/mod_dav_svn/repos.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/mod_dav_svn/repos.c (original) +++ subversion/branches/swig-py3/subversion/mod_dav_svn/repos.c Mon Jul 8 15:19:03 2019 @@ -1225,25 +1225,32 @@ create_private_resource(const dav_resour return &comb->res; } - -static void log_warning(void *baton, svn_error_t *err) +static void log_warning_req(void *baton, svn_error_t *err) { request_rec *r = baton; const char *continuation = ""; - /* ### hmm. the FS is cleaned up at request cleanup time. "r" might - ### not really be valid. we should probably put the FS into a - ### subpool to ensure it gets cleaned before the request. + /* Not showing file/line so no point in tracing */ + err = svn_error_purge_tracing(err); + while (err) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, "%s%s", + continuation, err->message); + continuation = "-"; + err = err->child; + } +} - ### is there a good way to create and use a subpool for all - ### of our functions ... ?? - */ +static void log_warning_conn(void *baton, svn_error_t *err) +{ + conn_rec *c = baton; + const char *continuation = ""; /* Not showing file/line so no point in tracing */ err = svn_error_purge_tracing(err); while (err) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, "%s%s", + ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c, "%s%s", continuation, err->message); continuation = "-"; err = err->child; @@ -1547,6 +1554,24 @@ cleanup_fs_access(void *data) return APR_SUCCESS; } +/* Context for cleanup handler. */ +struct cleanup_req_logging_baton +{ + svn_fs_t *fs; + conn_rec *connection; +}; + +static apr_status_t +cleanup_req_logging(void *data) +{ + struct cleanup_req_logging_baton *baton = data; + + /* The request about to be freed. Log future warnings with a connection + * context instead of a request context. */ + svn_fs_set_warning_func(baton->fs, log_warning_conn, baton->connection); + + return APR_SUCCESS; +} /* Helper func to construct a special 'parentpath' private resource. */ static dav_error * @@ -2180,6 +2205,7 @@ get_resource(request_rec *r, int had_slash; dav_locktoken_list *ltl; struct cleanup_fs_access_baton *cleanup_baton; + struct cleanup_req_logging_baton *cleanup_req_logging_baton; void *userdata; apr_hash_t *fs_config; @@ -2486,7 +2512,7 @@ get_resource(request_rec *r, repos->fs = svn_repos_fs(repos->repos); /* capture warnings during cleanup of the FS */ - svn_fs_set_warning_func(repos->fs, log_warning, r); + svn_fs_set_warning_func(repos->fs, log_warning_req, r); /* if an authenticated username is present, attach it to the FS */ if (r->user) @@ -2503,6 +2529,14 @@ get_resource(request_rec *r, apr_pool_cleanup_register(r->pool, cleanup_baton, cleanup_fs_access, apr_pool_cleanup_null); + /* We must degrade the logging context when the request is freed. */ + cleanup_req_logging_baton = + apr_pcalloc(r->pool, sizeof(*cleanup_req_logging_baton)); + cleanup_req_logging_baton->fs = repos->fs; + cleanup_req_logging_baton->connection = r->connection; + apr_pool_pre_cleanup_register(r->pool, cleanup_req_logging_baton, + cleanup_req_logging); + /* Create an access context based on the authenticated username. */ serr = svn_fs_create_access(&access_ctx, r->user, r->pool); if (serr) Modified: subversion/branches/swig-py3/subversion/svn/blame-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/blame-cmd.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/blame-cmd.c (original) +++ subversion/branches/swig-py3/subversion/svn/blame-cmd.c Mon Jul 8 15:19:03 2019 @@ -44,6 +44,7 @@ typedef struct blame_baton_t svn_stream_t *out; svn_stringbuf_t *sbuf; + svn_revnum_t start_revnum, end_revnum; int rev_maxlength; } blame_baton_t; @@ -54,15 +55,13 @@ typedef struct blame_baton_t XML to stdout. */ static svn_error_t * blame_receiver_xml(void *baton, - svn_revnum_t start_revnum, - svn_revnum_t end_revnum, apr_int64_t line_no, svn_revnum_t revision, apr_hash_t *rev_props, svn_revnum_t merged_revision, apr_hash_t *merged_rev_props, const char *merged_path, - const char *line, + const svn_string_t *line, svn_boolean_t local_change, apr_pool_t *pool) { @@ -170,15 +169,13 @@ print_line_info(svn_stream_t *out, /* This implements the svn_client_blame_receiver3_t interface. */ static svn_error_t * blame_receiver(void *baton, - svn_revnum_t start_revnum, - svn_revnum_t end_revnum, apr_int64_t line_no, svn_revnum_t revision, apr_hash_t *rev_props, svn_revnum_t merged_revision, apr_hash_t *merged_rev_props, const char *merged_path, - const char *line, + const svn_string_t *line, svn_boolean_t local_change, apr_pool_t *pool) { @@ -188,19 +185,19 @@ blame_receiver(void *baton, svn_boolean_t use_merged = FALSE; if (!bb->rev_maxlength) - { - svn_revnum_t max_revnum = MAX(start_revnum, end_revnum); - /* The standard column width for the revision number is 6 characters. - If the revision number can potentially be larger (i.e. if the end_revnum - is larger than 1000000), we increase the column width as needed. */ - - bb->rev_maxlength = 6; - while (max_revnum >= 1000000) - { - bb->rev_maxlength++; - max_revnum = max_revnum / 10; - } - } + { + svn_revnum_t max_revnum = MAX(bb->start_revnum, bb->end_revnum); + /* The standard column width for the revision number is 6 characters. + If the revision number can potentially be larger (i.e. if the end_revnum + is larger than 1000000), we increase the column width as needed. */ + + bb->rev_maxlength = 6; + while (max_revnum >= 1000000) + { + bb->rev_maxlength++; + max_revnum = max_revnum / 10; + } + } if (opt_state->use_merge_history) { @@ -237,7 +234,7 @@ blame_receiver(void *baton, bb->rev_maxlength, pool)); - return svn_stream_printf(out, pool, "%s%s", line, APR_EOL_STR); + return svn_stream_printf(out, pool, "%s%s", line->data, APR_EOL_STR); } @@ -333,7 +330,7 @@ svn_cl__blame(apr_getopt_t *os, const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *truepath; svn_opt_revision_t peg_revision; - svn_client_blame_receiver3_t receiver; + svn_client_blame_receiver4_t receiver; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); @@ -368,7 +365,8 @@ svn_cl__blame(apr_getopt_t *os, else receiver = blame_receiver; - err = svn_client_blame5(truepath, + err = svn_client_blame6(&bl.start_revnum, &bl.end_revnum, + truepath, &peg_revision, &opt_state->start_revision, &opt_state->end_revision, Modified: subversion/branches/swig-py3/subversion/svn/cl.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/cl.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/cl.h (original) +++ subversion/branches/swig-py3/subversion/svn/cl.h Mon Jul 8 15:19:03 2019 @@ -261,6 +261,7 @@ typedef struct svn_cl__opt_state_t svn_boolean_t mergeinfo_log; /* show log message in mergeinfo command */ svn_boolean_t remove_unversioned;/* remove unversioned items */ svn_boolean_t remove_ignored; /* remove ignored items */ + svn_boolean_t remove_added; /* reverting added item also removes it */ svn_boolean_t no_newline; /* do not output the trailing newline */ svn_boolean_t show_passwords; /* show cached passwords */ svn_boolean_t pin_externals; /* pin externals to last-changed revisions */ @@ -329,6 +330,7 @@ svn_opt_subcommand_t svn_cl__shelf_save, svn_cl__shelf_shelve, svn_cl__shelf_unshelve, + svn_cl__wc_copy_mods, svn_cl__status, svn_cl__switch, svn_cl__unlock, Modified: subversion/branches/swig-py3/subversion/svn/conflict-callbacks.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/conflict-callbacks.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/conflict-callbacks.c (original) +++ subversion/branches/swig-py3/subversion/svn/conflict-callbacks.c Mon Jul 8 15:19:03 2019 @@ -449,6 +449,8 @@ static const resolver_option_t builtin_r /* Options for incoming move vs local move. */ { "m", svn_client_conflict_option_both_moved_file_merge }, { "M", svn_client_conflict_option_both_moved_file_move_merge }, + { "m", svn_client_conflict_option_both_moved_dir_merge }, + { "M", svn_client_conflict_option_both_moved_dir_move_merge }, { NULL } }; Modified: subversion/branches/swig-py3/subversion/svn/revert-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/revert-cmd.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/revert-cmd.c (original) +++ subversion/branches/swig-py3/subversion/svn/revert-cmd.c Mon Jul 8 15:19:03 2019 @@ -71,7 +71,7 @@ svn_cl__revert(apr_getopt_t *os, opt_state->changelists, FALSE /* clear_changelists */, FALSE /* metadata_only */, - TRUE /*added_keep_local*/, + !opt_state->remove_added /*added_keep_local*/, ctx, scratch_pool); if (err && (err->apr_err == SVN_ERR_WC_INVALID_OPERATION_DEPTH) Modified: subversion/branches/swig-py3/subversion/svn/shelf-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/shelf-cmd.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/shelf-cmd.c (original) +++ subversion/branches/swig-py3/subversion/svn/shelf-cmd.c Mon Jul 8 15:19:03 2019 @@ -1207,3 +1207,27 @@ svn_cl__shelf_log(apr_getopt_t *os, return SVN_NO_ERROR; } + +/**************************************************************************/ + +/* This implements the `svn_opt_subcommand_t' interface. */ +svn_error_t * +svn_cl__wc_copy_mods(apr_getopt_t *os, + void *baton, + apr_pool_t *pool) +{ + svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; + const char *src_wc_abspath, *dst_wc_abspath; + + SVN_ERR(get_next_argument(&src_wc_abspath, os, pool, pool)); + SVN_ERR(svn_dirent_get_absolute(&src_wc_abspath, src_wc_abspath, pool)); + + SVN_ERR(get_next_argument(&dst_wc_abspath, os, pool, pool)); + SVN_ERR(svn_dirent_get_absolute(&dst_wc_abspath, dst_wc_abspath, pool)); + + SVN_ERR(svn_client__wc_copy_mods(src_wc_abspath, dst_wc_abspath, + ctx->notify_func2, ctx->notify_baton2, + ctx, pool)); + + return SVN_NO_ERROR; +} Modified: subversion/branches/swig-py3/subversion/svn/svn.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/svn.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/svn.c (original) +++ subversion/branches/swig-py3/subversion/svn/svn.c Mon Jul 8 15:19:03 2019 @@ -140,6 +140,7 @@ typedef enum svn_cl__longopt_t { opt_mergeinfo_log, opt_remove_unversioned, opt_remove_ignored, + opt_remove_added, opt_no_newline, opt_show_passwords, opt_pin_externals, @@ -421,6 +422,8 @@ const apr_getopt_option_t svn_cl__option {"remove-unversioned", opt_remove_unversioned, 0, N_("remove unversioned items")}, {"remove-ignored", opt_remove_ignored, 0, N_("remove ignored items")}, + {"remove-added", opt_remove_added, 0, + N_("reverting an added item will remove it from disk")}, {"no-newline", opt_no_newline, 0, N_("do not output the trailing newline")}, {"show-passwords", opt_show_passwords, 0, N_("show cached passwords")}, {"pin-externals", opt_pin_externals, 0, @@ -1765,7 +1768,8 @@ const svn_opt_subcommand_desc3_t svn_cl_ " For information about undoing already committed changes, search\n" " the output of 'svn help merge' for 'undo'.\n" )}, - {opt_targets, 'R', opt_depth, 'q', opt_changelist} }, + {opt_targets, 'R', opt_depth, 'q', opt_changelist, + opt_remove_added} }, { "status", svn_cl__status, {"stat", "st"}, {N_( "Print the status of working copy files and directories.\n" @@ -2134,6 +2138,18 @@ const svn_opt_subcommand_desc3_t svn_cl_ )}, {opt_drop, 'q', opt_dry_run, opt_force} }, + { "x-wc-copy-mods", svn_cl__wc_copy_mods, {0}, {N_( + "Copy local modifications from one WC to another.\n" + "usage: x-wc-copy-mods SRC_WC_PATH DST_WC_PATH\n" + "\n"), N_( + " The source and destination WC paths may be in the same WC or in different" + " WCs.\n" + "\n"), N_( + " This feature is EXPERIMENTAL. This command is likely to change\n" + " in the next release, and there is no promise of backward compatibility.\n" + )}, + }, + { NULL, NULL, {0}, {NULL}, {0} } }; @@ -2637,7 +2653,8 @@ sub_main(int *exit_code, int argc, const break; case opt_config_dir: SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); - opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool); + SVN_ERR(svn_dirent_internal_style_safe(&opt_state.config_dir, NULL, + utf8_opt_arg, pool, pool)); break; case opt_config_options: if (!opt_state.config_options) @@ -2806,6 +2823,9 @@ sub_main(int *exit_code, int argc, const case opt_remove_ignored: opt_state.remove_ignored = TRUE; break; + case opt_remove_added: + opt_state.remove_added = TRUE; + break; case opt_no_newline: case opt_strict: /* ### DEPRECATED */ opt_state.no_newline = TRUE; @@ -3220,7 +3240,10 @@ sub_main(int *exit_code, int argc, const { svn_node_kind_t kind; const char *local_abspath; - const char *fname = svn_dirent_internal_style(dash_F_arg, pool); + const char *fname; + + SVN_ERR(svn_dirent_internal_style_safe(&fname, NULL, dash_F_arg, + pool, pool)); err = svn_dirent_get_absolute(&local_abspath, fname, pool); Modified: subversion/branches/swig-py3/subversion/svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svn/util.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svn/util.c (original) +++ subversion/branches/swig-py3/subversion/svn/util.c Mon Jul 8 15:19:03 2019 @@ -163,6 +163,8 @@ svn_cl__merge_file_externally(const char arguments[5] = wc_path; arguments[6] = NULL; + /* Presumably apr_filepath_get() returns a valid path, so we don't have + to use the safe version of svn_dirent_internal_style() here. */ SVN_ERR(svn_io_run_cmd(svn_dirent_internal_style(cwd, pool), merge_tool, arguments, &exitcode, NULL, TRUE, NULL, NULL, NULL, pool)); Modified: subversion/branches/swig-py3/subversion/svnadmin/svnadmin.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnadmin/svnadmin.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnadmin/svnadmin.c (original) +++ subversion/branches/swig-py3/subversion/svnadmin/svnadmin.c Mon Jul 8 15:19:03 2019 @@ -42,6 +42,7 @@ #include "svn_time.h" #include "svn_user.h" #include "svn_xml.h" +#include "svn_fs.h" #include "private/svn_cmdline_private.h" #include "private/svn_opt_private.h" @@ -49,6 +50,7 @@ #include "private/svn_subr_private.h" #include "private/svn_cmdline_private.h" #include "private/svn_fspath.h" +#include "private/svn_fs_fs_private.h" #include "svn_private_config.h" @@ -114,6 +116,7 @@ static svn_opt_subcommand_t subcommand_lstxns, subcommand_pack, subcommand_recover, + subcommand_rev_size, subcommand_rmlocks, subcommand_rmtxns, subcommand_setlog, @@ -518,6 +521,17 @@ static const svn_opt_subcommand_desc3_t )}, {svnadmin__wait} }, + {"rev-size", subcommand_rev_size, {0}, {N_( + "usage: svnadmin rev-size REPOS_PATH -r REVISION\n" + "\n"), N_( + "Print the total size in bytes of the representation on disk of\n" + "revision REVISION.\n" + "\n"), N_( + "The size includes revision properties and excludes FSFS indexes.\n" + )}, + {'r', 'q', 'M'}, + { {'q', "print only the size and a newline"} } }, + {"rmlocks", subcommand_rmlocks, {0}, {N_( "usage: svnadmin rmlocks REPOS_PATH LOCKED_PATH...\n" "\n"), N_( @@ -2847,6 +2861,68 @@ subcommand_delrevprop(apr_getopt_t *os, } +/* Set *REV_SIZE to the total size in bytes of the representation on disk + * of revision REVISION in FS. + * + * This is implemented only for FSFS repositories, and otherwise returns + * an SVN_ERR_UNSUPPORTED_FEATURE error. + * + * The size includes revision properties and excludes FSFS indexes. + */ +static svn_error_t * +revision_size(apr_off_t *rev_size, + svn_fs_t *fs, + svn_revnum_t revision, + apr_pool_t *scratch_pool) +{ + svn_error_t *err; + svn_fs_fs__ioctl_revision_size_input_t input = {0}; + svn_fs_fs__ioctl_revision_size_output_t *output; + + input.revision = revision; + err = svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_REVISION_SIZE, + &input, (void **)&output, + check_cancel, NULL, scratch_pool, scratch_pool); + if (err && err->apr_err == SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE) + { + return svn_error_quick_wrapf(err, + _("Revision size query is not implemented " + "for the filesytem type found in '%s'"), + svn_fs_path(fs, scratch_pool)); + } + SVN_ERR(err); + + *rev_size = output->rev_size; + return SVN_NO_ERROR; +} + +/* This implements `svn_opt_subcommand_t'. */ +svn_error_t * +subcommand_rev_size(apr_getopt_t *os, void *baton, apr_pool_t *pool) +{ + struct svnadmin_opt_state *opt_state = baton; + svn_revnum_t revision; + apr_off_t rev_size; + svn_repos_t *repos; + + if (opt_state->start_revision.kind != svn_opt_revision_number + || opt_state->end_revision.kind != svn_opt_revision_unspecified) + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Invalid revision specifier")); + revision = opt_state->start_revision.value.number; + + SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool)); + SVN_ERR(revision_size(&rev_size, svn_repos_fs(repos), revision, pool)); + + if (opt_state->quiet) + SVN_ERR(svn_cmdline_printf(pool, "%"APR_OFF_T_FMT"\n", rev_size)); + else + SVN_ERR(svn_cmdline_printf(pool, _("%12"APR_OFF_T_FMT" bytes in revision %ld\n"), + rev_size, revision)); + + return SVN_NO_ERROR; +} + /** Main. **/ Modified: subversion/branches/swig-py3/subversion/svndumpfilter/svndumpfilter.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svndumpfilter/svndumpfilter.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svndumpfilter/svndumpfilter.c (original) +++ subversion/branches/swig-py3/subversion/svndumpfilter/svndumpfilter.c Mon Jul 8 15:19:03 2019 @@ -43,6 +43,7 @@ #include "svn_mergeinfo.h" #include "svn_version.h" +#include "private/svn_dirent_uri_private.h" #include "private/svn_repos_private.h" #include "private/svn_mergeinfo_private.h" #include "private/svn_cmdline_private.h" @@ -1467,7 +1468,7 @@ sub_main(int *exit_code, int argc, const /* Ensure that each prefix is UTF8-encoded, in internal style, and absolute. */ SVN_ERR(svn_utf_cstring_to_utf8(&prefix, os->argv[i], pool)); - prefix = svn_relpath__internal_style(prefix, pool); + SVN_ERR(svn_relpath__make_internal(&prefix, prefix, pool, pool)); if (prefix[0] != '/') prefix = apr_pstrcat(pool, "/", prefix, SVN_VA_NULL); APR_ARRAY_PUSH(opt_state.prefixes, const char *) = prefix; Modified: subversion/branches/swig-py3/subversion/svnfsfs/dump-index-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnfsfs/dump-index-cmd.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnfsfs/dump-index-cmd.c (original) +++ subversion/branches/swig-py3/subversion/svnfsfs/dump-index-cmd.c Mon Jul 8 15:19:03 2019 @@ -79,6 +79,7 @@ dump_index(const char *path, apr_pool_t *pool) { svn_fs_t *fs; + svn_fs_fs__ioctl_dump_index_input_t input = {0}; /* Check repository type and open it. */ SVN_ERR(open_fs(&fs, path, pool)); @@ -87,8 +88,10 @@ dump_index(const char *path, printf(" Start Length Type Revision Item Checksum\n"); /* Dump the whole index contents */ - SVN_ERR(svn_fs_fs__dump_index(fs, revision, dump_index_entry, NULL, - check_cancel, NULL, pool)); + input.revision = revision; + input.callback_func = dump_index_entry; + SVN_ERR(svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_DUMP_INDEX, &input, NULL, + check_cancel, NULL, pool, pool)); return SVN_NO_ERROR; } Modified: subversion/branches/swig-py3/subversion/svnfsfs/load-index-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnfsfs/load-index-cmd.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnfsfs/load-index-cmd.c (original) +++ subversion/branches/swig-py3/subversion/svnfsfs/load-index-cmd.c Mon Jul 8 15:19:03 2019 @@ -135,6 +135,7 @@ load_index(const char *path, svn_revnum_t revision = SVN_INVALID_REVNUM; apr_array_header_t *entries = apr_array_make(pool, 16, sizeof(void*)); apr_pool_t *iterpool = svn_pool_create(pool); + svn_fs_fs__ioctl_load_index_input_t ioctl_input = {0}; /* Check repository type and open it. */ SVN_ERR(open_fs(&fs, path, pool)); @@ -173,7 +174,10 @@ load_index(const char *path, } /* Rewrite the indexes. */ - SVN_ERR(svn_fs_fs__load_index(fs, revision, entries, iterpool)); + ioctl_input.revision = revision; + ioctl_input.entries = entries; + SVN_ERR(svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_LOAD_INDEX, &ioctl_input, NULL, + NULL, NULL, pool, pool)); svn_pool_destroy(iterpool); return SVN_NO_ERROR; Modified: subversion/branches/swig-py3/subversion/svnfsfs/stats-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnfsfs/stats-cmd.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnfsfs/stats-cmd.c (original) +++ subversion/branches/swig-py3/subversion/svnfsfs/stats-cmd.c Mon Jul 8 15:19:03 2019 @@ -500,15 +500,17 @@ svn_error_t * subcommand__stats(apr_getopt_t *os, void *baton, apr_pool_t *pool) { svnfsfs__opt_state *opt_state = baton; - svn_fs_fs__stats_t *stats; svn_fs_t *fs; + svn_fs_fs__ioctl_get_stats_input_t input = {0}; + svn_fs_fs__ioctl_get_stats_output_t *output; printf("Reading revisions\n"); SVN_ERR(open_fs(&fs, opt_state->repository_path, pool)); - SVN_ERR(svn_fs_fs__get_stats(&stats, fs, print_progress, NULL, - check_cancel, NULL, pool, pool)); - print_stats(stats, pool); + input.progress_func = print_progress; + SVN_ERR(svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_GET_STATS, &input, (void **)&output, + check_cancel, NULL, pool, pool)); + print_stats(output->stats, pool); return SVN_NO_ERROR; } Modified: subversion/branches/swig-py3/subversion/svnserve/logger.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnserve/logger.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnserve/logger.c (original) +++ subversion/branches/swig-py3/subversion/svnserve/logger.c Mon Jul 8 15:19:03 2019 @@ -88,19 +88,21 @@ logger__create(logger_t **logger, return SVN_NO_ERROR; } -void -logger__log_error(logger_t *logger, - svn_error_t *err, - repository_t *repository, - client_info_t *client_info) +static void +log_message(logger_t *logger, + const svn_error_t *err, + const char *prefix, + 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]; + const apr_size_t errstr_size = 8192; + char *errstr = apr_palloc(logger->pool, errstr_size); svn_error_clear(svn_mutex__lock(logger->mutex)); @@ -118,21 +120,22 @@ logger__log_error(logger_t *logger, continuation = ""; while (err) { + char errbuf[256]; 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_size_t len = apr_snprintf(errstr, errstr_size, "%" APR_PID_T_FMT - " %s %s %s %s ERR%s %s %ld %d ", + " %s %s %s %s %s%s %s %ld %d ", getpid(), timestr, remote_host, user, - repos, continuation, + repos, prefix, continuation, err->file ? err->file : "-", err->line, err->apr_err); len += escape_errorlog_item(errstr + len, message, - sizeof(errstr) - len); + errstr_size - len); /* Truncate for the terminator (as apr_snprintf does) */ - if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) { - len = sizeof(errstr) - sizeof(APR_EOL_STR); + if (len > errstr_size - sizeof(APR_EOL_STR)) { + len = errstr_size - sizeof(APR_EOL_STR); } memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR)); @@ -150,6 +153,24 @@ logger__log_error(logger_t *logger, } } +void +logger__log_error(logger_t *logger, + const svn_error_t *err, + repository_t *repository, + client_info_t *client_info) +{ + log_message(logger, err, "ERR", repository, client_info); +} + +void +logger__log_warning(logger_t *logger, + const svn_error_t *err, + repository_t *repository, + client_info_t *client_info) +{ + log_message(logger, err, "WARN", repository, client_info); +} + svn_error_t * logger__write(logger_t *logger, const char *errstr, Modified: subversion/branches/swig-py3/subversion/svnserve/logger.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnserve/logger.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnserve/logger.h (original) +++ subversion/branches/swig-py3/subversion/svnserve/logger.h Mon Jul 8 15:19:03 2019 @@ -64,14 +64,21 @@ logger__write(logger_t *logger, /* Write a description of ERR with additional information from REPOSITORY * and CLIENT_INFO to the log file managed by LOGGER. REPOSITORY as well * as CLIENT_INFO may be NULL. If either ERR or LOGGER are NULL, this - * becomes a no-op. + * becomes a no-op. Does not clear ERR. */ void logger__log_error(logger_t *logger, - svn_error_t *err, + const svn_error_t *err, repository_t *repository, client_info_t *client_info); +/* Like logger__log_error() but for warnings. */ +void +logger__log_warning(logger_t *logger, + const svn_error_t *err, + repository_t *repository, + client_info_t *client_info); + #ifdef __cplusplus } #endif /* __cplusplus */ Modified: subversion/branches/swig-py3/subversion/svnserve/serve.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/svnserve/serve.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/svnserve/serve.c (original) +++ subversion/branches/swig-py3/subversion/svnserve/serve.c Mon Jul 8 15:19:03 2019 @@ -107,15 +107,22 @@ typedef struct authz_baton_t { svn_ra_svn_conn_t *conn; } authz_baton_t; -/* svn_error_create() a new error, log_server_error() it, and - return it. */ +/* Log an error. */ static void -log_error(svn_error_t *err, server_baton_t *server) +log_error(const svn_error_t *err, server_baton_t *server) { logger__log_error(server->logger, err, server->repository, server->client_info); } +/* Log a warning. */ +static void +log_warning(const svn_error_t *err, server_baton_t *server) +{ + logger__log_warning(server->logger, err, server->repository, + server->client_info); +} + /* svn_error_create() a new error, log_server_error() it, and return it. */ static svn_error_t * @@ -294,7 +301,10 @@ static svn_error_t * load_authz_config(repository_t *repository, const char *repos_root, svn_config_t *cfg, - apr_pool_t *pool) + svn_repos_authz_warning_func_t warning_func, + void *warning_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { const char *authzdb_path; const char *groupsdb_path; @@ -313,17 +323,18 @@ load_authz_config(repository_t *reposito /* Canonicalize and add the base onto the authzdb_path (if needed). */ err = canonicalize_access_file(&authzdb_path, repository, - repos_root, pool); + repos_root, scratch_pool); /* Same for the groupsdb_path if it is present. */ if (groupsdb_path && !err) err = canonicalize_access_file(&groupsdb_path, repository, - repos_root, pool); + repos_root, scratch_pool); if (!err) - err = svn_repos_authz_read3(&repository->authzdb, authzdb_path, + err = svn_repos_authz_read4(&repository->authzdb, authzdb_path, groupsdb_path, TRUE, repository->repos, - pool, pool); + warning_func, warning_baton, + result_pool, scratch_pool); if (err) return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, err, NULL); @@ -3505,8 +3516,21 @@ get_deleted_rev(svn_ra_svn_conn_t *conn, svn_relpath_canonicalize(path, pool), pool); SVN_ERR(log_command(b, conn, pool, "get-deleted-rev")); SVN_ERR(trivial_auth_request(conn, pool, b)); - SVN_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision, - end_revision, &revision_deleted, pool)); + SVN_CMD_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision, + end_revision, &revision_deleted, pool)); + + /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly. + Instead, return SVN_ERR_ENTRY_MISSING_REVISION. A new enough client + knows that this means the answer to the query is SVN_INVALID_REVNUM. + (An older client reports this as an error.) */ + if (revision_deleted == SVN_INVALID_REVNUM) + SVN_CMD_ERR(svn_error_createf(SVN_ERR_ENTRY_MISSING_REVISION, NULL, + "svn protocol command 'get-deleted-rev': " + "path '%s' was not deleted in r%ld-%ld; " + "NOTE: newer clients handle this case " + "and do not report it as an error", + full_path, peg_revision, end_revision)); + SVN_ERR(svn_ra_svn__write_cmd_response(conn, pool, "r", revision_deleted)); return SVN_NO_ERROR; } @@ -3793,6 +3817,8 @@ find_repos(const char *url, repository_t *repository, svn_repos__config_pool_t *config_pool, apr_hash_t *fs_config, + svn_repos_authz_warning_func_t authz_warning_func, + void *authz_warning_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -3870,7 +3896,8 @@ find_repos(const char *url, SVN_ERR(load_pwdb_config(repository, cfg, config_pool, result_pool)); SVN_ERR(load_authz_config(repository, repository->repos_root, cfg, - result_pool)); + authz_warning_func, authz_warning_baton, + result_pool, scratch_pool)); /* Should we use Cyrus SASL? */ SVN_ERR(svn_config_get_bool(cfg, &sasl_requested, @@ -4092,6 +4119,16 @@ get_client_info(svn_ra_svn_conn_t *conn, return client_info; } +static void +handle_authz_warning(void *baton, + const svn_error_t *err, + apr_pool_t *scratch_pool) +{ + server_baton_t *const server_baton = baton; + log_warning(err, server_baton); + SVN_UNUSED(scratch_pool); +} + /* Construct the server baton for CONN using PARAMS and return it in *BATON. * It's lifetime is the same as that of CONN. SCRATCH_POOL */ @@ -4101,7 +4138,7 @@ construct_server_baton(server_baton_t ** serve_params_t *params, apr_pool_t *scratch_pool) { - svn_error_t *err, *io_err; + svn_error_t *err; apr_uint64_t ver; const char *client_url, *ra_client_string, *client_string; svn_ra_svn__list_t *caplist; @@ -4214,10 +4251,14 @@ construct_server_baton(server_baton_t ** } } + /* (*b) has the logger, repository and client_info set, so it can + be used as the authz_warning_baton that eventyally gets passed + to log_warning(). */ err = handle_config_error(find_repos(client_url, params->root, b->vhost, b->read_only, params->cfg, b->repository, params->config_pool, params->fs_config, + handle_authz_warning, b, conn_pool, scratch_pool), b); if (!err) @@ -4239,11 +4280,12 @@ construct_server_baton(server_baton_t ** } if (err) { - log_error(err, b); - io_err = svn_ra_svn__write_cmd_failure(conn, scratch_pool, err); - svn_error_clear(err); - SVN_ERR(io_err); - return svn_ra_svn__flush(conn, scratch_pool); + /* Report these errors to the client before closing the connection. */ + err = svn_error_compose_create(err, + svn_ra_svn__write_cmd_failure(conn, scratch_pool, err)); + err = svn_error_compose_create(err, + svn_ra_svn__flush(conn, scratch_pool)); + return err; } SVN_ERR(svn_fs_get_uuid(b->repository->fs, &b->repository->uuid, Propchange: subversion/branches/swig-py3/subversion/tests/ ------------------------------------------------------------------------------ --- svn:ignore (original) +++ svn:ignore Mon Jul 8 15:19:03 2019 @@ -6,4 +6,3 @@ Release *.o *~ .*~ -svnserveautocheck.pid Propchange: subversion/branches/swig-py3/subversion/tests/cmdline/ ------------------------------------------------------------------------------ --- svn:ignore (original) +++ svn:ignore Mon Jul 8 15:19:03 2019 @@ -1,5 +1,6 @@ svn-test-work httpd-* +svnserve-* .gdb_history *.pyc *.o Modified: subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py Mon Jul 8 15:19:03 2019 @@ -1694,7 +1694,7 @@ def inverted_group_membership(sbox): @Skip(svntest.main.is_ra_type_file) def group_member_empty_string(sbox): - "group definition ignores with empty member" + "group definition ignores empty member" sbox.build(create_wc = False) @@ -1710,6 +1710,27 @@ def group_member_empty_string(sbox): '--username', svntest.main.wc_author, sbox.repo_url) +@Issue(4802) +@Skip(svntest.main.is_ra_type_file) +def empty_group(sbox): + "empty group is ignored" + + sbox.build(create_wc = False) + + write_restrictive_svnserve_conf(sbox.repo_dir) + write_authz_file(sbox, + {"/" : ("$anonymous =\n" + "@empty = rw\n" + "@readonly = r\n")}, + {"groups": ("empty = \n" + "readonly = %s\n" % svntest.main.wc_author)}) + + expected_output = svntest.verify.UnorderedOutput(['A/\n', 'iota\n']) + svntest.actions.run_and_verify_svn(expected_output, [], + 'list', + '--username', svntest.main.wc_author, + sbox.repo_url) + ######################################################################## # Run the tests @@ -1749,6 +1770,7 @@ test_list = [ None, remove_access_after_commit, inverted_group_membership, group_member_empty_string, + empty_group, ] serial_only = True Modified: subversion/branches/swig-py3/subversion/tests/cmdline/commit_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/commit_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/commit_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/commit_tests.py Mon Jul 8 15:19:03 2019 @@ -3146,6 +3146,40 @@ def commit_issue4722_checksum(sbox): fp.write('abcdefghijklmnopqrstuvwxyz') sbox.simple_commit() +@XFail() +def commit_sees_tree_conflict_on_unversioned_path(sbox): + "commit sees tree conflict on unversioned path" + + sbox.build(empty=True) + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '.' + + # create a tree conflict victim at an unversioned path + sbox.simple_mkdir('topdir') + sbox.simple_commit() + sbox.simple_mkdir('topdir/subdir') + sbox.simple_commit() + sbox.simple_update() + sbox.simple_rm('topdir') + sbox.simple_commit() + sbox.simple_update() + svntest.actions.run_and_verify_svn( + None, [], + 'merge', '-c2', sbox.wc_dir, '--ignore-ancestry', '--accept', 'postpone') + # check that we did create a conflict + svntest.actions.run_and_verify_svn( + None, 'svn: E155015:.*existing.*conflict.*', + 'merge', '-c1', sbox.wc_dir, '--ignore-ancestry', '--accept', 'postpone') + + # attempt to commit; should fail + expected_err = "svn: E155015: .* '.*topdir' remains in conflict" + svntest.actions.run_and_verify_commit(sbox.wc_dir, None, None, + expected_err, + sbox.wc_dir) + + os.chdir(was_cwd) + ######################################################################## # Run the tests @@ -3225,6 +3259,7 @@ test_list = [ None, mkdir_conflict_proper_error, commit_xml, commit_issue4722_checksum, + commit_sees_tree_conflict_on_unversioned_path, ] if __name__ == '__main__': Modified: subversion/branches/swig-py3/subversion/tests/cmdline/dav_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/dav_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/dav_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/dav_tests.py Mon Jul 8 15:19:03 2019 @@ -69,12 +69,14 @@ def connect_other_dav_server(sbox): #---------------------------------------------------------------------- -@XFail() @SkipUnless(svntest.main.is_remote_http_connection_allowed) def connect_to_github_server(sbox): "connect to GitHub's SVN bridge" - github_mirror_url = 'https://github.com/apache/subversion/trunk' + #github_mirror_url = 'https://github.com/apache/subversion/trunk' + # FIXME: Subversion's mirror on GitHub seems to randomly return gateway + # errors (status 504), so use this more stable one instead. + github_mirror_url = 'https://github.com/apache/serf/trunk' # Skip this test if we can't connect to the GitHub server. # We check this here instead of in a SkipUnless() predicate decorator, Modified: subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout Mon Jul 8 15:19:03 2019 @@ -55,6 +55,7 @@ Available subcommands: x-shelf-save x-shelve x-unshelve + x-wc-copy-mods Subversion is a tool for version control. For additional information, see http://subversion.apache.org/ Modified: subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout Mon Jul 8 15:19:03 2019 @@ -55,6 +55,7 @@ Available subcommands: x-shelf-save x-shelve x-unshelve + x-wc-copy-mods Subversion is a tool for version control. For additional information, see http://subversion.apache.org/