You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2022/01/14 14:01:51 UTC
svn commit: r1897034 [22/37] - in /subversion/branches/multi-wc-format: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contrib/hook-scripts/ contrib/s...
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"