Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/io.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/io.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/io.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/io.c Fri Jan 14 14:01:45 2022 @@ -144,6 +144,14 @@ #ifdef WIN32 #if _WIN32_WINNT < 0x600 /* Does the SDK assume Windows Vista+? */ +typedef struct _FILE_BASIC_INFO { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +} FILE_BASIC_INFO, *PFILE_BASIC_INFO; + typedef struct _FILE_RENAME_INFO { BOOL ReplaceIfExists; HANDLE RootDirectory; @@ -155,8 +163,15 @@ 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 FileBasicInfo 0 #define FileRenameInfo 3 #define FileDispositionInfo 4 +#define FileAttributeTagInfo 9 #endif /* WIN32 < Vista */ /* One-time initialization of the late bound Windows API functions. */ @@ -169,19 +184,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 +368,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 +430,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 +443,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 +464,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 @@ -1532,7 +1583,7 @@ reown_file(const char *path, } /* Determine what the PERMS for a new file should be by looking at the - permissions of a temporary file that we create in DIRECTORY. + permissions of a temporary file that we create in DIRECTORY. DIRECTORY can be NULL in which case the system temporary dir is used. Unfortunately, umask() as defined in POSIX provides no thread-safe way to get at the current value of the umask, so what we're doing here is @@ -1622,13 +1673,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 +1700,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 +1809,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 +2001,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 +2080,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 +2134,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, @@ -2102,6 +2330,83 @@ svn_io__win_rename_open_file(apr_file_t return SVN_NO_ERROR; } +/* Number of micro-seconds between the beginning of the Windows epoch + * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970) + */ +#ifndef APR_DELTA_EPOCH_IN_USEC +#define APR_DELTA_EPOCH_IN_USEC APR_TIME_C(11644473600000000) +#endif + +svn_error_t * +svn_io__win_set_file_basic_info(apr_file_t *file, + const char *path, + apr_time_t set_mtime, + svn_boolean_t set_read_only, + apr_pool_t *pool) +{ + FILE_BASIC_INFO info; + HANDLE hFile; + apr_status_t status; + + apr_os_file_get(&hFile, file); + + if (set_read_only) + { + status = win32_get_file_information_by_handle(hFile, FileBasicInfo, + &info, sizeof(info)); + if (status) + { + return svn_error_wrap_apr(status, _("Can't get attributes of '%s'"), + svn_dirent_local_style(path, pool)); + } + } + + info.CreationTime.QuadPart = 0; + info.LastAccessTime.QuadPart = 0; + info.ChangeTime.QuadPart = 0; + + if (set_mtime == SVN_IO__WIN_TIME_UNCHANGED) + { + /* If you specify a value of zero for any of the XxxTime members of the + FILE_BASIC_INFORMATION structure, the ZwSetInformationFile function + keeps a file's current setting for that time. + https://docs.microsoft.com/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_basic_information#remarks + */ + info.LastWriteTime.QuadPart = 0; + } + else if (set_mtime == SVN_IO__WIN_TIME_SUSPEND_UPDATE) + { + /* File system updates the values of the LastAccessTime, LastWriteTime, + and ChangeTime members as appropriate after an I/O operation is + performed on a file. A driver or application can request that the + file system not update one or more of these members for I/O operations + that are performed on the caller's file handle by setting the + appropriate members to -1. + https://docs.microsoft.com/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_basic_information#remarks + */ + info.LastWriteTime.QuadPart = -1; + } + else + { + info.LastWriteTime.QuadPart = (set_mtime + APR_DELTA_EPOCH_IN_USEC) * 10; + } + + if (set_read_only) + info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + else + info.FileAttributes = 0; + + status = win32_set_file_information_by_handle(hFile, FileBasicInfo, + &info, sizeof(info)); + if (status) + { + return svn_error_wrap_apr(status, _("Can't set attributes of '%s'"), + svn_dirent_local_style(path, pool)); + } + + return SVN_NO_ERROR; +} + #endif /* WIN32 */ svn_error_t * @@ -2115,6 +2420,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 +2480,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 +2500,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 } @@ -2460,7 +2789,6 @@ svn_io__file_lock_autocreate(const char svn_error_t *svn_io_file_flush_to_disk(apr_file_t *file, apr_pool_t *pool) { - apr_os_file_t filehand; const char *fname; apr_status_t apr_err; @@ -2470,49 +2798,21 @@ svn_error_t *svn_io_file_flush_to_disk(a if (apr_err) return svn_error_wrap_apr(apr_err, _("Can't get file name")); - /* ### In apr 1.4+ we could delegate most of this function to - apr_file_sync(). The only major difference is that this doesn't - contain the retry loop for EINTR on linux. */ - - /* First make sure that any user-space buffered data is flushed. */ - SVN_ERR(svn_io_file_flush(file, pool)); - - apr_os_file_get(&filehand, file); - - /* Call the operating system specific function to actually force the - data to disk. */ - { -#ifdef WIN32 - - if (! FlushFileBuffers(filehand)) - return svn_error_wrap_apr(apr_get_os_error(), - _("Can't flush file '%s' to disk"), - try_utf8_from_internal_style(fname, pool)); - -#else - int rv; - - do { -#ifdef F_FULLFSYNC - rv = fcntl(filehand, F_FULLFSYNC, 0); -#else - rv = fsync(filehand); -#endif - } while (rv == -1 && APR_STATUS_IS_EINTR(apr_get_os_error())); + do { + apr_err = apr_file_datasync(file); + } while(APR_STATUS_IS_EINTR(apr_err)); - /* If the file is in a memory filesystem, fsync() may return - EINVAL. Presumably the user knows the risks, and we can just - ignore the error. */ - if (rv == -1 && APR_STATUS_IS_EINVAL(apr_get_os_error())) - return SVN_NO_ERROR; + /* If the file is in a memory filesystem, fsync() may return + EINVAL. Presumably the user knows the risks, and we can just + ignore the error. */ + if (APR_STATUS_IS_EINVAL(apr_err)) + return SVN_NO_ERROR; - if (rv == -1) - return svn_error_wrap_apr(apr_get_os_error(), - _("Can't flush file '%s' to disk"), - try_utf8_from_internal_style(fname, pool)); + if (apr_err) + return svn_error_wrap_apr(apr_err, + _("Can't flush file '%s' to disk"), + try_utf8_from_internal_style(fname, pool)); -#endif - } return SVN_NO_ERROR; } @@ -2554,7 +2854,7 @@ stringbuf_from_aprfile(svn_stringbuf_t * correct, for instance, because the underlying handle could be pointing to a pipe. We don't know that in advance, so attempt to read *one more* byte than necessary. If we get an EOF, then - we're done and we have succesfully avoided reading the file chunk- + we're done and we have successfully avoided reading the file chunk- by-chunk. If we don't, we fall through and do so to read the remaining part of the file. */ svn_boolean_t eof; @@ -2761,6 +3061,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); @@ -4242,7 +4548,45 @@ win32_file_rename(const WCHAR *from_path } if (!MoveFileExW(from_path_w, to_path_w, flags)) - return apr_get_os_error(); + { + apr_status_t err = apr_get_os_error(); + /* If the target file is read only NTFS reports EACCESS and + FAT/FAT32 reports EEXIST */ + if (APR_STATUS_IS_EACCES(err) || APR_STATUS_IS_EEXIST(err)) + { + DWORD attrs = GetFileAttributesW(to_path_w); + if (attrs == INVALID_FILE_ATTRIBUTES) + { + apr_status_t stat_err = apr_get_os_error(); + if (!(APR_STATUS_IS_ENOENT(stat_err) || SVN__APR_STATUS_IS_ENOTDIR(stat_err))) + /* We failed to stat the file, propagate the original error */ + return err; + } + else if (attrs & FILE_ATTRIBUTE_READONLY) + { + /* Try to set the destination file writable because Windows will + not allow us to rename when to_path is read-only, but will + allow renaming when from_path is read only. */ + attrs &= ~FILE_ATTRIBUTE_READONLY; + if (!SetFileAttributesW(to_path_w, attrs)) + { + err = apr_get_os_error(); + if (!(APR_STATUS_IS_ENOENT(err) || SVN__APR_STATUS_IS_ENOTDIR(err))) + /* We failed to set file attributes, propagate this new error */ + return err; + } + } + + /* NOTE: If the file is not read-only, we don't know if the file did + not have the read-only attribute in the first place or if this + attribute disappeared due to a race, so try to rename it anyway. + */ + if (!MoveFileExW(from_path_w, to_path_w, flags)) + return apr_get_os_error(); + } + else + return err; + } return APR_SUCCESS; } @@ -4266,18 +4610,6 @@ svn_io_file_rename2(const char *from_pat SVN_ERR(svn_io__utf8_to_unicode_longpath(&from_path_w, from_path_apr, pool)); SVN_ERR(svn_io__utf8_to_unicode_longpath(&to_path_w, to_path_apr, pool)); status = win32_file_rename(from_path_w, to_path_w, flush_to_disk); - - /* If the target file is read only NTFS reports EACCESS and - FAT/FAT32 reports EEXIST */ - if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status)) - { - /* Set the destination file writable because Windows will not - allow us to rename when to_path is read-only, but will - allow renaming when from_path is read only. */ - SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool)); - - status = win32_file_rename(from_path_w, to_path_w, flush_to_disk); - } WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w, flush_to_disk)); #elif defined(__OS2__) @@ -4499,8 +4831,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/multi-wc-format/subversion/libsvn_subr/iter.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/iter.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/iter.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/iter.c Fri Jan 14 14:01:45 2022 @@ -37,7 +37,6 @@ static svn_error_t internal_break_error __LINE__ /* line number */ }; -#if APR_VERSION_AT_LEAST(1, 4, 0) struct hash_do_baton { void *baton; @@ -59,7 +58,6 @@ int hash_do_callback(void *baton, return hdb->err == SVN_NO_ERROR; } -#endif svn_error_t * svn_iter_apr_hash(svn_boolean_t *completed, @@ -68,7 +66,6 @@ svn_iter_apr_hash(svn_boolean_t *complet void *baton, apr_pool_t *pool) { -#if APR_VERSION_AT_LEAST(1, 4, 0) struct hash_do_baton hdb; svn_boolean_t error_received; @@ -97,43 +94,6 @@ svn_iter_apr_hash(svn_boolean_t *complet } return hdb.err; -#else - svn_error_t *err = SVN_NO_ERROR; - apr_pool_t *iterpool = svn_pool_create(pool); - apr_hash_index_t *hi; - - for (hi = apr_hash_first(pool, hash); - ! err && hi; hi = apr_hash_next(hi)) - { - const void *key; - void *val; - apr_ssize_t len; - - svn_pool_clear(iterpool); - - apr_hash_this(hi, &key, &len, &val); - err = (*func)(baton, key, len, val, iterpool); - } - - if (completed) - *completed = ! err; - - if (err && err->apr_err == SVN_ERR_ITER_BREAK) - { - if (err != &internal_break_error) - /* Errors - except those created by svn_iter_break() - - need to be cleared when not further propagated. */ - svn_error_clear(err); - - err = SVN_NO_ERROR; - } - - /* Clear iterpool, because callers may clear the error but have no way - to clear the iterpool with potentially lots of allocated memory */ - svn_pool_destroy(iterpool); - - return err; -#endif } svn_error_t * Propchange: subversion/branches/multi-wc-format/subversion/libsvn_subr/lz4/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri Jan 14 14:01:45 2022 @@ -0,0 +1 @@ +.libs Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/mergeinfo.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/mergeinfo.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/mergeinfo.c Fri Jan 14 14:01:45 2022 @@ -44,8 +44,9 @@ /* Return TRUE iff the forward revision range FIRST wholly contains the * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has * the same inheritability. */ -static svn_boolean_t -range_contains(const svn_merge_range_t *first, const svn_merge_range_t *second, +static svn_error_t * +range_contains(svn_boolean_t *result, + const svn_merge_range_t *first, const svn_merge_range_t *second, svn_boolean_t consider_inheritance); @@ -457,21 +458,48 @@ combine_with_lastrange(const svn_merge_r } /* Convert a single svn_merge_range_t *RANGE back into a string. */ -static char * -range_to_string(const svn_merge_range_t *range, +static svn_error_t * +range_to_string(char **s, + const svn_merge_range_t *range, apr_pool_t *pool) { const char *mark = range->inheritable ? "" : SVN_MERGEINFO_NONINHERITABLE_STR; if (range->start == range->end - 1) - return apr_psprintf(pool, "%ld%s", range->end, mark); + *s = apr_psprintf(pool, "%ld%s", range->end, mark); else if (range->start - 1 == range->end) - return apr_psprintf(pool, "-%ld%s", range->start, mark); + *s = apr_psprintf(pool, "-%ld%s", range->start, mark); else if (range->start < range->end) - return apr_psprintf(pool, "%ld-%ld%s", range->start + 1, range->end, mark); + *s = apr_psprintf(pool, "%ld-%ld%s", range->start + 1, range->end, mark); + else if (range->start > range->end) + *s = apr_psprintf(pool, "%ld-%ld%s", range->start, range->end + 1, mark); else - return apr_psprintf(pool, "%ld-%ld%s", range->start, range->end + 1, mark); + { + return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL, + _("bad range {start=%ld,end=%ld,inheritable=%d}"), + range->start, range->end, range->inheritable); + } + + return SVN_NO_ERROR; +} + +/* Convert a single svn_merge_range_t *RANGE back into a string. */ +static char * +range_to_string_debug(const svn_merge_range_t *range, + apr_pool_t *pool) +{ + svn_error_t *err; + char *s; + + err = range_to_string(&s, range, pool); + if (err) + { + svn_error_clear(err); + s = apr_psprintf(pool, _("bad range {start=%ld,end=%ld,inheritable=%d}"), + range->start, range->end, range->inheritable); + } + return s; } /* Helper for svn_mergeinfo_parse() @@ -667,10 +695,10 @@ svn_rangelist__canonicalize(svn_rangelis "revision ranges '%s' and '%s' " "with different inheritance " "types"), - range_to_string(lastrange, - scratch_pool), - range_to_string(range, - scratch_pool)); + range_to_string_debug(lastrange, + scratch_pool), + range_to_string_debug(range, + scratch_pool)); } /* Combine overlapping or adjacent ranges with the @@ -678,7 +706,7 @@ svn_rangelist__canonicalize(svn_rangelis if (lastrange->inheritable == range->inheritable) { lastrange->end = MAX(range->end, lastrange->end); - svn_sort__array_delete(rangelist, i, 1); + SVN_ERR(svn_sort__array_delete2(rangelist, i, 1)); i--; } } @@ -788,490 +816,349 @@ svn_mergeinfo_parse(svn_mergeinfo_t *mer return err; } -/* Cleanup after svn_rangelist_merge2 when it modifies the ending range of - a single rangelist element in-place. - - If *RANGE_INDEX is not a valid element in RANGELIST do nothing. Otherwise - ensure that RANGELIST[*RANGE_INDEX]->END does not adjoin or overlap any - subsequent ranges in RANGELIST. - - If overlap is found, then remove, modify, and/or add elements to RANGELIST - as per the invariants for rangelists documented in svn_mergeinfo.h. If - RANGELIST[*RANGE_INDEX]->END adjoins a subsequent element then combine the - elements if their inheritability permits -- The inheritance of intersecting - and adjoining ranges is handled as per svn_mergeinfo_merge2. Upon return - set *RANGE_INDEX to the index of the youngest element modified, added, or - adjoined to RANGELIST[*RANGE_INDEX]. +static const char * +rangelist_to_string_debug(const svn_rangelist_t *rl, + apr_pool_t *pool) +{ + svn_string_t *rls; + svn_error_t *err; - Note: Adjoining rangelist elements are those where the end rev of the older - element is equal to the start rev of the younger element. + err = svn_rangelist_to_string(&rls, rl, pool); + if (err) + { + char *s = apr_psprintf(pool, _("<bad rangelist [%d ranges]: %s>"), + rl->nelts, err->message); + svn_error_clear(err); + return s; + } + return rls->data; +} - Any new elements inserted into RANGELIST are allocated in RESULT_POOL.*/ -static void -adjust_remaining_ranges(svn_rangelist_t *rangelist, - int *range_index, - apr_pool_t *result_pool) +static svn_boolean_t +rangelist_is_sorted(const svn_rangelist_t *rangelist) { int i; - int starting_index; - int elements_to_delete = 0; - svn_merge_range_t *modified_range; - - if (*range_index >= rangelist->nelts) - return; - starting_index = *range_index + 1; - modified_range = APR_ARRAY_IDX(rangelist, *range_index, svn_merge_range_t *); - - for (i = *range_index + 1; i < rangelist->nelts; i++) + for (i = 1; i < rangelist->nelts; i++) { - svn_merge_range_t *next_range = APR_ARRAY_IDX(rangelist, i, - svn_merge_range_t *); + const svn_merge_range_t *lastrange + = APR_ARRAY_IDX(rangelist, i-1, svn_merge_range_t *); + const svn_merge_range_t *thisrange + = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); - /* If MODIFIED_RANGE doesn't adjoin or overlap the next range in - RANGELIST then we are finished. */ - if (modified_range->end < next_range->start) - break; + if (svn_sort_compare_ranges(&lastrange, &thisrange) > 0) + return FALSE; + } + return TRUE; +} - /* Does MODIFIED_RANGE adjoin NEXT_RANGE? */ - if (modified_range->end == next_range->start) - { - if (modified_range->inheritable == next_range->inheritable) - { - /* Combine adjoining ranges with the same inheritability. */ - modified_range->end = next_range->end; - elements_to_delete++; - } - else - { - /* Cannot join because inheritance differs. */ - (*range_index)++; - } - break; - } +/* Mergeinfo inheritance or absence in a rangelist interval */ +enum rangelist_interval_kind_t { MI_NONE, MI_NON_INHERITABLE, MI_INHERITABLE }; - /* Alright, we know MODIFIED_RANGE overlaps NEXT_RANGE, but how? */ - if (modified_range->end > next_range->end) - { - /* NEXT_RANGE is a proper subset of MODIFIED_RANGE and the two - don't share the same end range. */ - if (modified_range->inheritable - || (modified_range->inheritable == next_range->inheritable)) - { - /* MODIFIED_RANGE absorbs NEXT_RANGE. */ - elements_to_delete++; - } - else - { - /* NEXT_RANGE is a proper subset MODIFIED_RANGE but - MODIFIED_RANGE is non-inheritable and NEXT_RANGE is - inheritable. This means MODIFIED_RANGE is truncated, - NEXT_RANGE remains, and the portion of MODIFIED_RANGE - younger than NEXT_RANGE is added as a separate range: - ______________________________________________ - | | - M MODIFIED_RANGE N - | (!inheritable) | - |______________________________________________| - | | - O NEXT_RANGE P - | (inheritable)| - |______________| - | - V - _______________________________________________ - | | | | - M MODIFIED_RANGE O NEXT_RANGE P NEW_RANGE N - | (!inheritable) | (inheritable)| (!inheritable)| - |________________|______________|_______________| - */ - svn_merge_range_t *new_modified_range = - apr_palloc(result_pool, sizeof(*new_modified_range)); - new_modified_range->start = next_range->end; - new_modified_range->end = modified_range->end; - new_modified_range->inheritable = FALSE; - modified_range->end = next_range->start; - (*range_index) += 2 + elements_to_delete; - svn_sort__array_insert(rangelist, &new_modified_range, - *range_index); - /* Recurse with the new range. */ - adjust_remaining_ranges(rangelist, range_index, result_pool); - break; - } - } - else if (modified_range->end == next_range->end) - { - /* NEXT_RANGE is a proper subset MODIFIED_RANGE and share - the same end range. */ - if (modified_range->inheritable - || (modified_range->inheritable == next_range->inheritable)) - { - /* MODIFIED_RANGE absorbs NEXT_RANGE. */ - elements_to_delete++; - } - else - { - /* The intersection between MODIFIED_RANGE and NEXT_RANGE is - absorbed by the latter. */ - modified_range->end = next_range->start; - (*range_index)++; - } - break; - } - else - { - /* NEXT_RANGE and MODIFIED_RANGE intersect but NEXT_RANGE is not - a proper subset of MODIFIED_RANGE, nor do the two share the - same end revision, i.e. they overlap. */ - if (modified_range->inheritable == next_range->inheritable) - { - /* Combine overlapping ranges with the same inheritability. */ - modified_range->end = next_range->end; - elements_to_delete++; - } - else if (modified_range->inheritable) - { - /* MODIFIED_RANGE absorbs the portion of NEXT_RANGE it overlaps - and NEXT_RANGE is truncated. */ - next_range->start = modified_range->end; - (*range_index)++; - } - else - { - /* NEXT_RANGE absorbs the portion of MODIFIED_RANGE it overlaps - and MODIFIED_RANGE is truncated. */ - modified_range->end = next_range->start; - (*range_index)++; - } - break; - } +/* A rangelist interval: like svn_merge_range_t but an interval can represent + * a gap in the rangelist (kind = MI_NONE). */ +typedef struct rangelist_interval_t +{ + svn_revnum_t start, end; + enum rangelist_interval_kind_t kind; +} rangelist_interval_t; + +/* Iterator for intervals in a rangelist. */ +typedef struct rangelist_interval_iterator_t { + /* iteration state: */ + const svn_rangelist_t *rl; /* input */ + int i; /* current interval is this range in RL or the gap before it */ + svn_boolean_t in_range; /* current interval is range RL[I], not a gap? */ + + /* current interval: */ + rangelist_interval_t interval; +} rangelist_interval_iterator_t; + +/* Update IT->interval to match the current iteration state of IT. + * Return the iterator, or NULL if the iteration has reached its end. + */ +static rangelist_interval_iterator_t * +rlii_update(rangelist_interval_iterator_t *it) +{ + const svn_merge_range_t *range + = (it->i < it->rl->nelts + ? APR_ARRAY_IDX(it->rl, it->i, void *) : NULL); + + if (!range) + return NULL; + + if (!it->in_range) + { + it->interval.start + = (it->i > 0 + ? APR_ARRAY_IDX(it->rl, it->i - 1, svn_merge_range_t *)->end + : 0); + it->interval.end = range->start; + it->interval.kind = MI_NONE; + } + else + { + it->interval.start = range->start; + it->interval.end = range->end; + it->interval.kind + = (range->inheritable ? MI_INHERITABLE : MI_NON_INHERITABLE); } + return it; +} - if (elements_to_delete) - svn_sort__array_delete(rangelist, starting_index, elements_to_delete); +/* Move to the next interval, which might be a zero-length interval. + * Return IT, or return NULL at the end of iteration. */ +static rangelist_interval_iterator_t * +rlii_next_any_interval(rangelist_interval_iterator_t *it) +{ + /* Should be called before iteration is finished. */ + if (it->i >= it->rl->nelts) + return NULL; + + /* If we are in a range, move to the next pre-range gap; + * else, move from this pre-range gap into this range. */ + if (it->in_range) + it->i++; + it->in_range = !it->in_range; + return it; } -#if 0 /* Temporary debug helper code */ -static svn_error_t * -dual_dump(const char *prefix, - const svn_rangelist_t *rangelist, - const svn_rangelist_t *changes, - apr_pool_t *scratch_pool) +/* Return an iterator pointing at the first non-zero-length interval in RL, + * or NULL if there are none. */ +static rangelist_interval_iterator_t * +rlii_first(const svn_rangelist_t *rl, + apr_pool_t *pool) { - svn_string_t *rls, *chg; + rangelist_interval_iterator_t *it = apr_palloc(pool, sizeof(*it)); - SVN_ERR(svn_rangelist_to_string(&rls, rangelist, scratch_pool)); - SVN_ERR(svn_rangelist_to_string(&chg, changes, scratch_pool)); + it->rl = rl; + it->i = 0; + it->in_range = FALSE; - SVN_DBG(("%s: %s / %s", prefix, rls->data, chg->data)); - return SVN_NO_ERROR; + /* Update, and skip empty intervals */ + while ((it = rlii_update(it)) && it->interval.start == it->interval.end) + { + it = rlii_next_any_interval(it); + } + return it; } -#endif -svn_error_t * -svn_rangelist_merge2(svn_rangelist_t *rangelist, - const svn_rangelist_t *chg, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +/* Move to the next non-empty interval. + * Intervals will be generated in this sequence: + * (0, MI_NONE, RL[0]->start), // i=0, !in_range + * (RL[0]->start, MI_* RL[0]->end), // i=0, in_range + * (RL[0]->end, MI_NONE, RL[1]->start), + * (RL[1]->start, MI_* RL[1]->end), + * ... + * (RL[n-2]->end, MI_NONE, RL[n-1]->start), + * (RL[n-1]->start, MI_* RL[n-1]->end), + * but excluding empty intervals. + * Return IT, or return NULL at the end of iteration. */ +static rangelist_interval_iterator_t * +rlii_next(rangelist_interval_iterator_t *it) { - svn_rangelist_t *changes; - int i = 0; - int j; + it = rlii_next_any_interval(it); - SVN_ERR(svn_rangelist__canonicalize(rangelist, scratch_pool)); + /* Update, and skip empty intervals */ + while ((it = rlii_update(it)) && it->interval.start == it->interval.end) + { + it = rlii_next_any_interval(it); + } + return it; +} - /* We may modify CHANGES, so make a copy in SCRATCH_POOL. */ - changes = svn_rangelist_dup(chg, scratch_pool); - SVN_ERR(svn_rangelist__canonicalize(changes, scratch_pool)); +/* Rangelist builder. Accumulates consecutive intervals, combining them + * when possible. */ +typedef struct rangelist_builder_t { + svn_rangelist_t *rl; /* rangelist to build */ + rangelist_interval_t accu_interval; /* current interval accumulator */ + apr_pool_t *pool; /* from which to allocate ranges */ +} rangelist_builder_t; - for (j = 0; j < changes->nelts; j++) - { - svn_merge_range_t *range; - svn_merge_range_t *change = - APR_ARRAY_IDX(changes, j, svn_merge_range_t *); - int res; +/* Return an initialized rangelist builder. */ +static rangelist_builder_t * +rl_builder_new(svn_rangelist_t *rl, + apr_pool_t *pool) +{ + rangelist_builder_t *b = apr_pcalloc(pool, sizeof(*b)); - range = (i < rangelist->nelts) - ? APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *) - : NULL; - - if (!range || change->end < range->start) - { - /* No overlap, nor adjoin, copy change to result range */ - svn_merge_range_t *chg_copy = svn_merge_range_dup(change, - result_pool); - svn_sort__array_insert(rangelist, &chg_copy, i++); - continue; - } - else if ((change->start > range->end) - || (change->start == range->end - && change->inheritable != range->inheritable)) - { - /* No overlap, nor adjoin. Check next range item against change */ - i++; - j--; - continue; - } + b->rl = rl; + /* b->accu_interval = {0, 0, RL_NONE} */ + b->pool = pool; + return b; +} - if (change->start < range->start - && range->inheritable != change->inheritable - && ! (change->inheritable && range_contains(change, range, FALSE)) - && ! (range->inheritable && range_contains(range, change, FALSE))) - { - /* Can't fold change into existing range. - Insert new range before range */ +/* Flush the last accumulated interval in the rangelist builder B. */ +static void +rl_builder_flush(rangelist_builder_t *b) +{ + if (b->accu_interval.kind > MI_NONE) + { + svn_merge_range_t *mrange = apr_pcalloc(b->pool, sizeof(*mrange)); + mrange->start = b->accu_interval.start; + mrange->end = b->accu_interval.end; + mrange->inheritable = (b->accu_interval.kind == MI_INHERITABLE); + APR_ARRAY_PUSH(b->rl, svn_merge_range_t *) = mrange; + } +} - svn_merge_range_t *chg_copy = svn_merge_range_dup(change, - result_pool); +/* Add a new INTERVAL to the rangelist builder B. */ +static void +rl_builder_add_interval(rangelist_builder_t *b, + const rangelist_interval_t *interval) +{ + SVN_ERR_ASSERT_NO_RETURN(interval->start < interval->end); + SVN_ERR_ASSERT_NO_RETURN(interval->start == b->accu_interval.end); - chg_copy->start = MIN(change->start, range->start); - if (! change->inheritable) - chg_copy->end = range->start; - else - range->start = change->end; + /* Extend the accumulating interval, or end it and start another? */ + if (interval->kind == b->accu_interval.kind) + { + b->accu_interval.end = interval->end; + } + else + { + /* Push the accumulated interval onto the building rangelist. */ + rl_builder_flush(b); + /* Start accumulating a new interval */ + b->accu_interval = *interval; + } +} - svn_sort__array_insert(rangelist, &chg_copy, i++); +/* Set RL_OUT to the union (merge) of RL1 and RL2. + * On entry, RL_OUT must be an empty rangelist. + * + * Each range added to RL_OUT will be either shallow-copied from RL1 or + * allocated from RESULT_POOL. + */ +static svn_error_t * +rangelist_merge(svn_rangelist_t *rl_out, + const svn_rangelist_t *rl1, + const svn_rangelist_t *rl2, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + rangelist_interval_iterator_t *it[2]; + rangelist_builder_t *rl_builder = rl_builder_new(rl_out, result_pool); + svn_revnum_t r_last = 0; + + /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rl1));*/ + /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rl2));*/ + SVN_ERR_ASSERT(rangelist_is_sorted(rl1)); + SVN_ERR_ASSERT(rangelist_is_sorted(rl2)); + SVN_ERR_ASSERT(rl_out->nelts == 0); + + /* Initialize the input iterators and the output generator */ + it[0] = rlii_first(rl1, scratch_pool); + it[1] = rlii_first(rl2, scratch_pool); + + /* Keep choosing the next input revision (whether a start or end of a range) + * at which to consider making an output transition. */ + while (it[0] || it[1]) + { + svn_revnum_t r_next = !it[1] ? it[0]->interval.end + : !it[0] ? it[1]->interval.end + : MIN(it[0]->interval.end, it[1]->interval.end); + rangelist_interval_t interval; + + interval.start = r_last; + interval.end = r_next; + interval.kind = !it[1] ? it[0]->interval.kind + : !it[0] ? it[1]->interval.kind + : MAX(it[0]->interval.kind, it[1]->interval.kind); + + /* Accumulate */ + SVN_ERR_ASSERT(interval.start < interval.end); + rl_builder_add_interval(rl_builder, &interval); + + /* if we have used up either or both input intervals, increment them */ + if (it[0] && it[0]->interval.end <= r_next) + it[0] = rlii_next(it[0]); + if (it[1] && it[1]->interval.end <= r_next) + it[1] = rlii_next(it[1]); - change->start = chg_copy->end; - if (change->start >= change->end) - continue; /* No overlap with range left */ - } - else - { - range->start = MIN(range->start, change->start); - } + r_last = interval.end; + } + rl_builder_flush(rl_builder); + return SVN_NO_ERROR; +} - SVN_ERR_ASSERT(change->start >= range->start); +svn_error_t * +svn_rangelist_merge2(svn_rangelist_t *rangelist, + const svn_rangelist_t *chg, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_error_t *err; + svn_rangelist_t *rangelist_orig; - res = svn_sort_compare_ranges(&range, &change); +#ifdef SVN_DEBUG + SVN_ERR_ASSERT(rangelist_is_sorted(rangelist)); + SVN_ERR_ASSERT(rangelist_is_sorted(chg)); +#endif - if (res == 0) - { - /* Only when merging two non-inheritable ranges is the result also - non-inheritable. In all other cases ensure an inheritable - result. */ - if (range->inheritable || change->inheritable) - range->inheritable = TRUE; - i++; - continue; - } - else if (res < 0) /* CHANGE is younger than RANGE */ - { - if (range->end == change->start) - { - /* RANGE and CHANGE adjoin */ - if (range->inheritable == change->inheritable) - { - /* RANGE and CHANGE have the same inheritability so - RANGE expands to absord CHANGE. */ - range->end = change->end; - adjust_remaining_ranges(rangelist, &i, result_pool); - continue; - } - else - { - /* RANGE and CHANGE adjoin, but have different - inheritability. Since RANGE is older, just - move on to the next RANGE. */ - SVN_ERR_MALFUNCTION(); - } - } - else - { - /* RANGE and CHANGE overlap, but how? */ - if ((range->inheritable == change->inheritable) - || range->inheritable) - { - /* If CHANGE is a proper subset of RANGE, it absorbs RANGE - with no adjustment otherwise only the intersection is - absorbed and CHANGE is truncated. */ - if (range->end >= change->end) - continue; - else - { - change->start = range->end; - j--; - continue; - } - } - else - { - /* RANGE is non-inheritable and CHANGE is inheritable. */ - if (range->start < change->start) - { - /* CHANGE absorbs intersection with RANGE and RANGE - is truncated. */ - svn_merge_range_t *range_copy = - svn_merge_range_dup(range, result_pool); - range_copy->end = change->start; - range->start = change->start; - svn_sort__array_insert(rangelist, &range_copy, i++); - j--; - continue; - } - else - { - /* CHANGE and RANGE share the same start rev, but - RANGE is considered older because its end rev - is older. */ - range->inheritable = TRUE; - change->start = range->end; - j--; - continue; - } - } - } - } - else /* res > 0, CHANGE is older than RANGE */ - { - if (change->end == range->start) - { - /* RANGE and CHANGE adjoin */ - if (range->inheritable == change->inheritable) - { - /* RANGE and CHANGE have the same inheritability so we - can simply combine the two in place. */ - range->start = change->start; - continue; - } - else - { - /* RANGE and CHANGE have different inheritability so insert - a copy of CHANGE into RANGELIST. */ - SVN_ERR_MALFUNCTION(); /* Already handled */ - } - } - else - { - /* RANGE and CHANGE overlap. */ - if (range->inheritable == change->inheritable) - { - /* RANGE and CHANGE have the same inheritability so we - can simply combine the two in place... */ - range->start = change->start; - if (range->end < change->end) - { - /* ...but if RANGE is expanded ensure that we don't - violate any rangelist invariants. */ - range->end = change->end; - adjust_remaining_ranges(rangelist, &i, result_pool); - } - continue; - } - else if (range->inheritable) - { - if (change->start < range->start) - { - /* RANGE is inheritable so absorbs any part of CHANGE - it overlaps. CHANGE is truncated and the remainder - inserted into RANGELIST. */ - SVN_ERR_MALFUNCTION(); /* Already handled */ - } - else - { - /* CHANGE and RANGE share the same start rev, but - CHANGE is considered older because CHANGE->END is - older than RANGE->END. */ - continue; - } - } - else - { - /* RANGE is non-inheritable and CHANGE is inheritable. */ - if (change->start < range->start) - { - if (change->end == range->end) - { - /* RANGE is a proper subset of CHANGE and share the - same end revision, so set RANGE equal to CHANGE. */ - range->start = change->start; - range->inheritable = TRUE; - continue; - } - else if (change->end > range->end) - { - /* RANGE is a proper subset of CHANGE and CHANGE has - a younger end revision, so set RANGE equal to its - intersection with CHANGE and truncate CHANGE. */ - range->start = change->start; - range->inheritable = TRUE; - change->start = range->end; - j--; - continue; - } - else - { - /* CHANGE and RANGE overlap. Set RANGE equal to its - intersection with CHANGE and take the remainder - of RANGE and insert it into RANGELIST. */ - svn_merge_range_t *range_copy = - svn_merge_range_dup(range, result_pool); - range_copy->start = change->end; - range->start = change->start; - range->end = change->end; - range->inheritable = TRUE; - svn_sort__array_insert(rangelist, &range_copy, ++i); - continue; - } - } - else - { - /* CHANGE and RANGE share the same start rev, but - CHANGE is considered older because its end rev - is older. - - Insert the intersection of RANGE and CHANGE into - RANGELIST and then set RANGE to the non-intersecting - portion of RANGE. */ - svn_merge_range_t *range_copy = - svn_merge_range_dup(range, result_pool); - range_copy->end = change->end; - range_copy->inheritable = TRUE; - range->start = change->end; - svn_sort__array_insert(rangelist, &range_copy, i++); - continue; - } - } - } - } - SVN_ERR_MALFUNCTION(); /* Unreachable */ - } + /* Move the original rangelist aside. A shallow copy suffices, + * as rangelist_merge() won't modify its inputs. */ + rangelist_orig = apr_array_copy(scratch_pool, rangelist); + apr_array_clear(rangelist); + err = svn_error_trace(rangelist_merge(rangelist, rangelist_orig, chg, + result_pool, scratch_pool)); #ifdef SVN_DEBUG - SVN_ERR_ASSERT(svn_rangelist__is_canonical(rangelist)); + if (err) + { + err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, err, + "svn_rangelist_merge2( %s / %s ): internal error", + rangelist_to_string_debug(rangelist_orig, scratch_pool), + rangelist_to_string_debug(chg, scratch_pool)); + } + else if (! svn_rangelist__is_canonical(rangelist) + && svn_rangelist__is_canonical(rangelist_orig) + && svn_rangelist__is_canonical(chg)) + { + err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL, + "svn_rangelist_merge2( %s / %s ): canonical inputs, " + "non-canonical result ( %s )", + rangelist_to_string_debug(rangelist_orig, scratch_pool), + rangelist_to_string_debug(chg, scratch_pool), + rangelist_to_string_debug(rangelist, scratch_pool)); + } #endif - return SVN_NO_ERROR; + return err; } -/* Return TRUE iff the forward revision ranges FIRST and SECOND overlap and - * (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */ -static svn_boolean_t -range_intersect(const svn_merge_range_t *first, const svn_merge_range_t *second, +/* Set *RESULT to TRUE iff the forward revision ranges FIRST and SECOND overlap + * and (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */ +static svn_error_t * +range_intersect(svn_boolean_t *result, + const svn_merge_range_t *first, const svn_merge_range_t *second, svn_boolean_t consider_inheritance) { - SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first)); - SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second)); + SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first)); + SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second)); - return (first->start + 1 <= second->end) - && (second->start + 1 <= first->end) - && (!consider_inheritance - || (!(first->inheritable) == !(second->inheritable))); + *result = (first->start + 1 <= second->end) + && (second->start + 1 <= first->end) + && (!consider_inheritance + || (!(first->inheritable) == !(second->inheritable))); + return SVN_NO_ERROR; } -/* Return TRUE iff the forward revision range FIRST wholly contains the +/* Set *RESULT to TRUE iff the forward revision range FIRST wholly contains the * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has * the same inheritability. */ -static svn_boolean_t -range_contains(const svn_merge_range_t *first, const svn_merge_range_t *second, +static svn_error_t * +range_contains(svn_boolean_t *result, + const svn_merge_range_t *first, const svn_merge_range_t *second, svn_boolean_t consider_inheritance) { - SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first)); - SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second)); + SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first)); + SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second)); - return (first->start <= second->start) && (second->end <= first->end) - && (!consider_inheritance - || (!(first->inheritable) == !(second->inheritable))); + *result = (first->start <= second->start) && (second->end <= first->end) + && (!consider_inheritance + || (!(first->inheritable) == !(second->inheritable))); + return SVN_NO_ERROR; } /* Swap start and end fields of RANGE. */ @@ -1390,6 +1277,7 @@ rangelist_intersect_or_remove(svn_rangel while (i1 < rangelist1->nelts && i2 < rangelist2->nelts) { svn_merge_range_t *elt1, *elt2; + svn_boolean_t elt1_contains_elt2, elt1_intersects_elt2; elt1 = APR_ARRAY_IDX(rangelist1, i1, svn_merge_range_t *); @@ -1405,6 +1293,10 @@ rangelist_intersect_or_remove(svn_rangel elt2 = &working_elt2; + SVN_ERR(range_contains(&elt1_contains_elt2, + elt1, elt2, consider_inheritance)); + SVN_ERR(range_intersect(&elt1_intersects_elt2, + elt1, elt2, consider_inheritance)); /* If the rangelist2 range is contained completely in the rangelist1, we increment the rangelist2. If the ranges intersect, and match exactly, we increment both @@ -1413,7 +1305,7 @@ rangelist_intersect_or_remove(svn_rangel the removal of rangelist1 from rangelist2, and possibly change the rangelist2 to the remaining portion of the right part of the removal, to test against. */ - if (range_contains(elt1, elt2, consider_inheritance)) + if (elt1_contains_elt2) { if (!do_remove) { @@ -1434,7 +1326,7 @@ rangelist_intersect_or_remove(svn_rangel if (elt2->start == elt1->start && elt2->end == elt1->end) i1++; } - else if (range_intersect(elt1, elt2, consider_inheritance)) + else if (elt1_intersects_elt2) { if (elt2->start < elt1->start) { @@ -1977,18 +1869,21 @@ svn_rangelist_to_string(svn_string_t **o { int i; svn_merge_range_t *range; + char *s; /* Handle the elements that need commas at the end. */ for (i = 0; i < rangelist->nelts - 1; i++) { range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); - svn_stringbuf_appendcstr(buf, range_to_string(range, pool)); + SVN_ERR(range_to_string(&s, range, pool)); + svn_stringbuf_appendcstr(buf, s); svn_stringbuf_appendcstr(buf, ","); } /* Now handle the last element, which needs no comma. */ range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); - svn_stringbuf_appendcstr(buf, range_to_string(range, pool)); + SVN_ERR(range_to_string(&s, range, pool)); + svn_stringbuf_appendcstr(buf, s); } *output = svn_stringbuf__morph_into_string(buf); Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/object_pool.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/object_pool.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/object_pool.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/object_pool.c Fri Jan 14 14:01:45 2022 @@ -174,7 +174,7 @@ add_object_ref(object_ref_t *object_ref, /* Make sure the reference gets released automatically. Since POOL might be a parent pool of OBJECT_REF->OBJECT_POOL, - to the reference counting update before destroing any of the + to the reference counting update before destroying any of the pool hierarchy. */ apr_pool_pre_cleanup_register(pool, object_ref, object_ref_cleanup); } @@ -321,7 +321,7 @@ svn_object_pool__insert(void **object, { *object = NULL; SVN_MUTEX__WITH_LOCK(object_pool->mutex, - insert(object, object_pool, key, item, + insert(object, object_pool, key, item, item_pool, result_pool)); return SVN_NO_ERROR; } Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/opt.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/opt.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/opt.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/opt.c Fri Jan 14 14:01:45 2022 @@ -211,12 +211,16 @@ svn_opt_subcommand_takes_option4(const s /* Print the canonical command name for CMD, and all its aliases, to STREAM. If HELP is set, print CMD's help string too, in which case - obtain option usage from OPTIONS_TABLE. */ + obtain option usage from OPTIONS_TABLE. + + Include global and experimental options iff VERBOSE is true. + */ static svn_error_t * print_command_info3(const svn_opt_subcommand_desc3_t *cmd, const apr_getopt_option_t *options_table, const int *global_options, svn_boolean_t help, + svn_boolean_t verbose, apr_pool_t *pool, FILE *stream) { @@ -251,6 +255,7 @@ print_command_info3(const svn_opt_subcom const apr_getopt_option_t *option; const char *long_alias; svn_boolean_t have_options = FALSE; + svn_boolean_t have_experimental = FALSE; SVN_ERR(svn_cmdline_fprintf(stream, pool, ": ")); @@ -279,6 +284,17 @@ print_command_info3(const svn_opt_subcom if (option && option->description) { const char *optstr; + + if (option->name && strncmp(option->name, "x-", 2) == 0) + { + if (verbose && !have_experimental) + SVN_ERR(svn_cmdline_fputs(_("\nExperimental options:\n"), + stream, pool)); + have_experimental = TRUE; + if (!verbose) + continue; + } + format_option(&optstr, option, long_alias, TRUE, pool); SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n", optstr)); @@ -286,7 +302,7 @@ print_command_info3(const svn_opt_subcom } } /* And global options too */ - if (global_options && *global_options) + if (verbose && global_options && *global_options) { SVN_ERR(svn_cmdline_fputs(_("\nGlobal options:\n"), stream, pool)); @@ -310,6 +326,9 @@ print_command_info3(const svn_opt_subcom } } + if (!verbose && global_options && *global_options) + SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show global and experimental options.)\n"), + stream, pool)); if (have_options) SVN_ERR(svn_cmdline_fprintf(stream, pool, "\n")); } @@ -324,23 +343,37 @@ print_generic_help_body3(const char *hea const svn_opt_subcommand_desc3_t *cmd_table, const apr_getopt_option_t *opt_table, const char *footer, + svn_boolean_t with_experimental, apr_pool_t *pool, FILE *stream) { - int i = 0; + svn_boolean_t have_experimental = FALSE; + int i; if (header) SVN_ERR(svn_cmdline_fputs(header, stream, pool)); - while (cmd_table[i].name) + for (i = 0; cmd_table[i].name; i++) { + if (strncmp(cmd_table[i].name, "x-", 2) == 0) + { + if (with_experimental && !have_experimental) + SVN_ERR(svn_cmdline_fputs(_("\nExperimental subcommands:\n"), + stream, pool)); + have_experimental = TRUE; + if (!with_experimental) + continue; + } SVN_ERR(svn_cmdline_fputs(" ", stream, pool)); SVN_ERR(print_command_info3(cmd_table + i, opt_table, - NULL, FALSE, + NULL, FALSE, FALSE, pool, stream)); SVN_ERR(svn_cmdline_fputs("\n", stream, pool)); - i++; } + if (have_experimental && !with_experimental) + SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show experimental subcommands.)\n"), + stream, pool)); + SVN_ERR(svn_cmdline_fputs("\n", stream, pool)); if (footer) @@ -349,17 +382,19 @@ print_generic_help_body3(const char *hea return SVN_NO_ERROR; } -void -svn_opt_print_generic_help3(const char *header, - const svn_opt_subcommand_desc3_t *cmd_table, - const apr_getopt_option_t *opt_table, - const char *footer, - apr_pool_t *pool, FILE *stream) +static void +print_generic_help(const char *header, + const svn_opt_subcommand_desc3_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + svn_boolean_t with_experimental, + apr_pool_t *pool, FILE *stream) { svn_error_t *err; - err = print_generic_help_body3(header, cmd_table, opt_table, footer, pool, - stream); + err = print_generic_help_body3(header, cmd_table, opt_table, footer, + with_experimental, + pool, stream); /* Issue #3014: * Don't print anything on broken pipes. The pipe was likely @@ -373,13 +408,29 @@ svn_opt_print_generic_help3(const char * svn_error_clear(err); } - void -svn_opt_subcommand_help4(const char *subcommand, - const svn_opt_subcommand_desc3_t *table, - const apr_getopt_option_t *options_table, - const int *global_options, - apr_pool_t *pool) +svn_opt_print_generic_help3(const char *header, + const svn_opt_subcommand_desc3_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + apr_pool_t *pool, FILE *stream) +{ + print_generic_help(header, cmd_table, opt_table, footer, + TRUE, pool, stream); +} + + +/* The body of svn_opt_subcommand_help4(), which see. + * + * VERBOSE means show also the subcommand's global and experimental options. + */ +static void +subcommand_help(const char *subcommand, + const svn_opt_subcommand_desc3_t *table, + const apr_getopt_option_t *options_table, + const int *global_options, + svn_boolean_t verbose, + apr_pool_t *pool) { const svn_opt_subcommand_desc3_t *cmd = svn_opt_get_canonical_subcommand3(table, subcommand); @@ -387,7 +438,7 @@ svn_opt_subcommand_help4(const char *sub if (cmd) err = print_command_info3(cmd, options_table, global_options, - TRUE, pool, stdout); + TRUE, verbose, pool, stdout); else err = svn_cmdline_fprintf(stderr, pool, _("\"%s\": unknown command.\n\n"), subcommand); @@ -400,6 +451,17 @@ svn_opt_subcommand_help4(const char *sub } } +void +svn_opt_subcommand_help4(const char *subcommand, + const svn_opt_subcommand_desc3_t *table, + const apr_getopt_option_t *options_table, + const int *global_options, + apr_pool_t *pool) +{ + subcommand_help(subcommand, table, options_table, global_options, + TRUE, pool); +} + /*** Parsing revision and date options. ***/ @@ -1185,9 +1247,9 @@ svn_opt_print_help5(apr_getopt_t *os, for (i = 0; i < targets->nelts; i++) { - svn_opt_subcommand_help4(APR_ARRAY_IDX(targets, i, const char *), - cmd_table, option_table, - global_options, pool); + subcommand_help(APR_ARRAY_IDX(targets, i, const char *), + cmd_table, option_table, global_options, + verbose, pool); } } else if (print_version) /* just --version */ @@ -1197,12 +1259,9 @@ svn_opt_print_help5(apr_getopt_t *os, quiet, verbose, pool)); } else if (os && !targets->nelts) /* `-h', `--help', or `help' */ - svn_opt_print_generic_help3(header, - cmd_table, - option_table, - footer, - pool, - stdout); + print_generic_help(header, cmd_table, option_table, footer, + verbose, + pool, stdout); else /* unknown option or cmd */ SVN_ERR(svn_cmdline_fprintf(stderr, pool, _("Type '%s help' for usage.\n"), pgm_name)); Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/path.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/path.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/path.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/path.c Fri Jan 14 14:01:45 2022 @@ -590,7 +590,7 @@ svn_path_is_ancestor(const char *path1, { apr_size_t path1_len = strlen(path1); - /* If path1 is empty and path2 is not absoulte, then path1 is an ancestor. */ + /* If path1 is empty and path2 is not absolute, then path1 is an ancestor. */ if (SVN_PATH_IS_EMPTY(path1)) return *path2 != '/'; Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/pool.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/pool.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/pool.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/pool.c Fri Jan 14 14:01:45 2022 @@ -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) @@ -151,16 +151,6 @@ svn_pool_create_allocator(svn_boolean_t } -/* - * apr_pool_create_core_ex was introduced in APR 1.3.0, then - * deprecated and renamed to apr_pool_create_unmanaged_ex in 1.3.3. - * Since our minimum requirement is APR 1.3.0, one or the other of - * these functions will always be available. - */ -#if !APR_VERSION_AT_LEAST(1,3,3) -#define apr_pool_create_unmanaged_ex apr_pool_create_core_ex -#endif - /* Private function that creates an unmanaged pool. */ apr_pool_t * svn_pool__create_unmanaged(svn_boolean_t thread_safe) Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/prompt.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/prompt.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/prompt.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/prompt.c Fri Jan 14 14:01:45 2022 @@ -262,7 +262,7 @@ terminal_puts(const char *string, termin /* These codes can be returned from terminal_getc instead of a character. */ #define TERMINAL_NONE 0x80000 /* no character read, retry */ -#define TERMINAL_DEL (TERMINAL_NONE + 1) /* the input was a deleteion */ +#define TERMINAL_DEL (TERMINAL_NONE + 1) /* the input was a deletion */ #define TERMINAL_EOL (TERMINAL_NONE + 2) /* end of input/end of line */ #define TERMINAL_EOF (TERMINAL_NONE + 3) /* end of file during input */ Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/sorts.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/sorts.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/sorts.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/sorts.c Fri Jan 14 14:01:45 2022 @@ -34,6 +34,8 @@ #include "svn_error.h" #include "private/svn_sorts_private.h" +#include "svn_private_config.h" + /*** svn_sort__hash() ***/ @@ -299,15 +301,20 @@ svn_sort__array_lookup(const apr_array_h return compare_func(result, key) ? NULL : result; } -void -svn_sort__array_insert(apr_array_header_t *array, - const void *new_element, - int insert_index) +svn_error_t * +svn_sort__array_insert2(apr_array_header_t *array, + const void *new_element, + int insert_index) { int elements_to_move; char *new_position; - assert(0 <= insert_index && insert_index <= array->nelts); + if (insert_index < 0 || insert_index > array->nelts) + return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL, + _("svn_sort__array_insert2: Attempted insert " + "at index %d in array length %d"), + insert_index, array->nelts); + elements_to_move = array->nelts - insert_index; /* before bumping nelts */ /* Grow the array, allocating a new space at the end. Note: this can @@ -322,31 +329,35 @@ svn_sort__array_insert(apr_array_header_ /* Copy in the new element */ memcpy(new_position, new_element, array->elt_size); + return SVN_NO_ERROR; } -void -svn_sort__array_delete(apr_array_header_t *arr, - int delete_index, - int elements_to_delete) -{ - /* Do we have a valid index and are there enough elements? */ - if (delete_index >= 0 - && delete_index < arr->nelts - && elements_to_delete > 0 - && (arr->nelts - delete_index) >= elements_to_delete) - { - /* If we are not deleting a block of elements that extends to the end - of the array, then we need to move the remaining elements to keep - the array contiguous. */ - if ((elements_to_delete + delete_index) < arr->nelts) - memmove( - arr->elts + arr->elt_size * delete_index, - arr->elts + (arr->elt_size * (delete_index + elements_to_delete)), - arr->elt_size * (arr->nelts - elements_to_delete - delete_index)); - - /* Delete the last ELEMENTS_TO_DELETE elements. */ - arr->nelts -= elements_to_delete; - } +svn_error_t * +svn_sort__array_delete2(apr_array_header_t *arr, + int delete_index, + int elements_to_delete) +{ + if (!(delete_index >= 0 + && delete_index < arr->nelts + && elements_to_delete > 0 + && (arr->nelts - delete_index) >= elements_to_delete)) + return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL, + _("svn_sort__array_delete2: Attempted delete " + "at index %d, %d elements, in array length %d"), + delete_index, elements_to_delete, arr->nelts); + + /* If we are deleting a block of elements that does not extend to the end + of the array, then we need to move the remaining elements to keep + the array contiguous. */ + if ((elements_to_delete + delete_index) < arr->nelts) + memmove( + arr->elts + arr->elt_size * delete_index, + arr->elts + (arr->elt_size * (delete_index + elements_to_delete)), + arr->elt_size * (arr->nelts - elements_to_delete - delete_index)); + + /* Delete the last ELEMENTS_TO_DELETE elements. */ + arr->nelts -= elements_to_delete; + return SVN_NO_ERROR; } void Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/sqlite3wrapper.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/sqlite3wrapper.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_subr/sqlite3wrapper.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_subr/sqlite3wrapper.c Fri Jan 14 14:01:45 2022 @@ -25,6 +25,8 @@ /* Include sqlite3 inline, making all symbols private. */ #ifdef SVN_SQLITE_INLINE # define SQLITE_OMIT_DEPRECATED 1 +# define SQLITE_DEFAULT_MEMSTATUS 0 +# define SQLITE_OMIT_WAL 1 # define SQLITE_API static # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) # pragma GCC diagnostic ignored "-Wunreachable-code"
