You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/15 10:52:18 UTC
svn commit: r1532250 [22/37] - in /subversion/branches/cache-server: ./
build/ build/ac-macros/ build/generator/ build/generator/swig/
build/generator/templates/ contrib/client-side/emacs/ contrib/hook-scripts/
contrib/server-side/fsfsfixer/ contrib/se...
Modified: subversion/branches/cache-server/subversion/libsvn_subr/hash.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/hash.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/hash.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/hash.c Tue Oct 15 08:52:06 2013
@@ -31,6 +31,7 @@
#include <apr_hash.h>
#include <apr_file_io.h>
+#include "svn_private_config.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
@@ -42,8 +43,6 @@
#include "private/svn_dep_compat.h"
#include "private/svn_subr_private.h"
-#include "svn_private_config.h"
-
@@ -576,20 +575,16 @@ svn_hash__get_bool(apr_hash_t *hash, con
/*** Optimized hash function ***/
-/* Optimized version of apr_hashfunc_default in APR 1.4.5 and earlier.
- * It assumes that the CPU has 32-bit multiplications with high throughput
- * of at least 1 operation every 3 cycles. Latency is not an issue. Another
- * optimization is a mildly unrolled main loop and breaking the dependency
- * chain within the loop.
- *
- * Note that most CPUs including Intel Atom, VIA Nano, ARM feature the
- * assumed pipelined multiplication circuitry. They can do one MUL every
- * or every other cycle.
- *
- * The performance is ultimately limited by the fact that most CPUs can
- * do only one LOAD and only one BRANCH operation per cycle. The best we
- * can do is to process one character per cycle - provided the processor
- * is wide enough to do 1 LOAD, COMPARE, BRANCH, MUL and ADD per cycle.
+/* apr_hashfunc_t optimized for the key that we use in SVN: paths and
+ * property names. Its primary goal is speed for keys of known length.
+ *
+ * Since strings tend to spawn large value spaces (usually differ in many
+ * bits with differences spanning a larger section of the key), we can be
+ * quite sloppy extracting a hash value. The more keys there are in a
+ * hash container, the more bits of the value returned by this function
+ * will be used. For a small number of string keys, choosing bits from any
+ * any fix location close to the tail of those keys would usually be good
+ * enough to prevent high collision rates.
*/
static unsigned int
hashfunc_compatible(const char *char_key, apr_ssize_t *klen)
@@ -600,37 +595,29 @@ hashfunc_compatible(const char *char_key
apr_ssize_t i;
if (*klen == APR_HASH_KEY_STRING)
+ *klen = strlen(char_key);
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+ for (p = key, i = *klen; i >= 4; i-=4, p+=4)
{
- for (p = key; ; p+=4)
- {
- unsigned int new_hash = hash * 33 * 33 * 33 * 33;
- if (!p[0]) break;
- new_hash += p[0] * 33 * 33 * 33;
- if (!p[1]) break;
- new_hash += p[1] * 33 * 33;
- if (!p[2]) break;
- new_hash += p[2] * 33;
- if (!p[3]) break;
- hash = new_hash + p[3];
- }
- for (; *p; p++)
- hash = hash * 33 + *p;
+ apr_uint32_t chunk = *(apr_uint32_t *)p;
- *klen = p - key;
+ /* the ">> 17" part gives upper bits in the chunk a chance to make
+ some impact as well */
+ hash = hash * 33 * 33 * 33 * 33 + chunk + (chunk >> 17);
}
- else
+#else
+ for (p = key, i = *klen; i >= 4; i-=4, p+=4)
{
- for (p = key, i = *klen; i >= 4; i-=4, p+=4)
- {
- hash = hash * 33 * 33 * 33 * 33
- + p[0] * 33 * 33 * 33
- + p[1] * 33 * 33
- + p[2] * 33
- + p[3];
- }
- for (; i; i--, p++)
- hash = hash * 33 + *p;
+ hash = hash * 33 * 33 * 33 * 33
+ + p[0] * 33 * 33 * 33
+ + p[1] * 33 * 33
+ + p[2] * 33
+ + p[3];
}
+#endif
+ for (; i; i--, p++)
+ hash = hash * 33 + *p;
return hash;
}
Modified: subversion/branches/cache-server/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/io.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/io.c Tue Oct 15 08:52:06 2013
@@ -51,6 +51,11 @@
#include <arch/win32/apr_arch_file_io.h>
#endif
+#if APR_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_types.h"
#include "svn_dirent_uri.h"
@@ -61,7 +66,6 @@
#include "svn_pools.h"
#include "svn_utf.h"
#include "svn_config.h"
-#include "svn_private_config.h"
#include "svn_ctype.h"
#include "private/svn_atomic.h"
@@ -139,6 +143,26 @@
#endif
#endif
+#ifdef WIN32
+/* One-time initialization of the late bound Windows API functions. */
+static volatile svn_atomic_t win_dynamic_imports_state = 0;
+
+/* Pointer to GetFinalPathNameByHandleW function from kernel32.dll. */
+typedef DWORD (WINAPI *GETFINALPATHNAMEBYHANDLE)(
+ HANDLE hFile,
+ apr_wchar_t *lpszFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
+static GETFINALPATHNAMEBYHANDLE get_final_path_name_by_handle_proc = NULL;
+
+/* Forward declaration. */
+static svn_error_t * io_win_read_link(svn_string_t **dest,
+ const char *path,
+ apr_pool_t *pool);
+
+#endif
+
/* Forward declaration */
static apr_status_t
dir_is_empty(const char *dir, apr_pool_t *pool);
@@ -660,7 +684,7 @@ svn_io_read_link(svn_string_t **dest,
const char *path,
apr_pool_t *pool)
{
-#ifdef HAVE_READLINK
+#if defined(HAVE_READLINK)
svn_string_t dest_apr;
const char *path_apr;
char buf[1025];
@@ -681,6 +705,8 @@ svn_io_read_link(svn_string_t **dest,
/* ### Cast needed, one of these interfaces is wrong */
return svn_utf_string_to_utf8((const svn_string_t **)dest, &dest_apr, pool);
+#elif defined(WIN32)
+ return io_win_read_link(dest, path, pool);
#else
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Symbolic links are not supported on this "
@@ -1140,9 +1166,11 @@ svn_io_make_dir_recursively(const char *
return SVN_NO_ERROR;
}
-svn_error_t *svn_io_file_create(const char *file,
- const char *contents,
- apr_pool_t *pool)
+svn_error_t *
+svn_io_file_create_binary(const char *file,
+ const char *contents,
+ apr_size_t length,
+ apr_pool_t *pool)
{
apr_file_t *f;
apr_size_t written;
@@ -1152,25 +1180,57 @@ svn_error_t *svn_io_file_create(const ch
(APR_WRITE | APR_CREATE | APR_EXCL),
APR_OS_DEFAULT,
pool));
- if (contents && *contents)
- err = svn_io_file_write_full(f, contents, strlen(contents),
- &written, pool);
+ if (length)
+ err = svn_io_file_write_full(f, contents, length, &written, pool);
+ err = svn_error_compose_create(
+ err,
+ svn_io_file_close(f, pool));
- return svn_error_trace(
- svn_error_compose_create(err,
- svn_io_file_close(f, pool)));
+ if (err)
+ {
+ /* Our caller doesn't know if we left a file or not if we return
+ an error. Better to cleanup after ourselves if we created the
+ file. */
+ return svn_error_trace(
+ svn_error_compose_create(
+ err,
+ svn_io_remove_file2(file, TRUE, pool)));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_file_create(const char *file,
+ const char *contents,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_io_file_create_binary(file, contents,
+ contents
+ ? strlen(contents)
+ : 0,
+ pool));
}
-svn_error_t *svn_io_dir_file_copy(const char *src_path,
- const char *dest_path,
- const char *file,
- apr_pool_t *pool)
+svn_error_t *
+svn_io_file_create_empty(const char *file,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_io_file_create_binary(file, "", 0, pool));
+}
+
+svn_error_t *
+svn_io_dir_file_copy(const char *src_path,
+ const char *dest_path,
+ const char *file,
+ apr_pool_t *pool)
{
const char *file_dest_path = svn_dirent_join(dest_path, file, pool);
const char *file_src_path = svn_dirent_join(src_path, file, pool);
- return svn_io_copy_file(file_src_path, file_dest_path, TRUE, pool);
+ return svn_error_trace(
+ svn_io_copy_file(file_src_path, file_dest_path, TRUE, pool));
}
@@ -1697,6 +1757,46 @@ static apr_status_t io_utf8_to_unicode_p
*t = L'\\';
return APR_SUCCESS;
}
+
+/* copy of the apr function unicode_to_utf8_path since apr doesn't export this
+ * one */
+static apr_status_t io_unicode_to_utf8_path(char* retstr, apr_size_t retlen,
+ const apr_wchar_t* srcstr)
+{
+ /* Skip the leading 4 characters if the path begins \\?\, or substitute
+ * // for the \\?\UNC\ path prefix, allocating the maximum string
+ * length based on the remaining string, plus the trailing null.
+ * then transform \\'s back into /'s since the \\?\ form never
+ * allows '/' path seperators, and APR always uses '/'s.
+ */
+ apr_size_t srcremains = wcslen(srcstr) + 1;
+ apr_status_t rv;
+ char *t = retstr;
+ if (srcstr[0] == L'\\' && srcstr[1] == L'\\' &&
+ srcstr[2] == L'?' && srcstr[3] == L'\\') {
+ if (srcstr[4] == L'U' && srcstr[5] == L'N' &&
+ srcstr[6] == L'C' && srcstr[7] == L'\\') {
+ srcremains -= 8;
+ srcstr += 8;
+ retstr[0] = '\\';
+ retstr[1] = '\\';
+ retlen -= 2;
+ t += 2;
+ }
+ else {
+ srcremains -= 4;
+ srcstr += 4;
+ }
+ }
+
+ if ((rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen))) {
+ return rv;
+ }
+ if (srcremains) {
+ return APR_ENAMETOOLONG;
+ }
+ return APR_SUCCESS;
+}
#endif
static apr_status_t io_win_file_attrs_set(const char *fname,
@@ -1756,6 +1856,83 @@ static apr_status_t io_win_file_attrs_se
return APR_SUCCESS;
}
+static svn_error_t *win_init_dynamic_imports(void *baton, apr_pool_t *pool)
+{
+ get_final_path_name_by_handle_proc = (GETFINALPATHNAMEBYHANDLE)
+ GetProcAddress(GetModuleHandleA("kernel32.dll"),
+ "GetFinalPathNameByHandleW");
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t * io_win_read_link(svn_string_t **dest,
+ const char *path,
+ apr_pool_t *pool)
+{
+#if APR_HAS_UNICODE_FS
+ SVN_ERR(svn_atomic__init_once(&win_dynamic_imports_state,
+ win_init_dynamic_imports, NULL, pool));
+
+ if (get_final_path_name_by_handle_proc)
+ {
+ DWORD rv;
+ apr_status_t status;
+ apr_file_t *file;
+ apr_os_file_t filehand;
+ apr_wchar_t wdest[APR_PATH_MAX];
+ char buf[APR_PATH_MAX];
+
+ /* reserve one char for terminating zero. */
+ DWORD wdest_len = sizeof(wdest)/sizeof(wdest[0]) - 1;
+
+ status = apr_file_open(&file, path, APR_OPENINFO, APR_OS_DEFAULT, pool);
+
+ if (status)
+ return svn_error_wrap_apr(status,
+ _("Can't read contents of link"));
+
+ apr_os_file_get(&filehand, file);
+
+ rv = get_final_path_name_by_handle_proc(
+ filehand, wdest, wdest_len,
+ FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+
+ /* Save error code. */
+ status = apr_get_os_error();
+
+ /* Close file/directory handle in any case. */
+ apr_file_close(file);
+
+ /* GetFinaPathNameByHandleW returns number of characters copied to
+ * output buffer. Returns zero on error. Returns required buffer size
+ * if supplied buffer is not enough. */
+ if (rv > wdest_len || rv == 0)
+ {
+ return svn_error_wrap_apr(status,
+ _("Can't read contents of link"));
+ }
+
+ /* GetFinaPathNameByHandleW doesn't add terminating NUL. */
+ wdest[rv] = 0;
+
+ status = io_unicode_to_utf8_path(buf, sizeof(buf), wdest);
+ if (status)
+ return svn_error_wrap_apr(status,
+ _("Can't read contents of link"));
+
+ *dest = svn_string_create(buf, pool);
+
+ return SVN_NO_ERROR;
+ }
+ else
+#endif
+ {
+ return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("Symbolic links are not supported on this "
+ "platform"));
+ }
+}
+
#endif
svn_error_t *
@@ -2091,11 +2268,12 @@ svn_error_t *svn_io_file_flush_to_disk(a
{
apr_os_file_t filehand;
+ /* ### 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(do_io_file_wrapper_cleanup(file, apr_file_flush(file),
- N_("Can't flush file '%s'"),
- N_("Can't flush stream"),
- pool));
+ SVN_ERR(svn_io_file_flush(file, pool));
apr_os_file_get(&filehand, file);
@@ -2112,7 +2290,11 @@ svn_error_t *svn_io_file_flush_to_disk(a
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()));
/* If the file is in a memory filesystem, fsync() may return
@@ -2152,36 +2334,35 @@ stringbuf_from_aprfile(svn_stringbuf_t *
svn_error_t *err;
svn_stringbuf_t *res = NULL;
apr_size_t res_initial_len = SVN__STREAM_CHUNK_SIZE;
- char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
+ char *buf;
/* If our caller wants us to check the size of the file for
efficient memory handling, we'll try to do so. */
if (check_size)
{
- apr_status_t status;
-
- /* If our caller didn't tell us the file's name, we'll ask APR
- if it knows the name. No problem if we can't figure it out. */
- if (! filename)
- {
- const char *filename_apr;
- if (! (status = apr_file_name_get(&filename_apr, file)))
- filename = filename_apr;
- }
+ apr_finfo_t finfo;
- /* If we now know the filename, try to stat(). If we succeed,
- we know how to allocate our stringbuf. */
- if (filename)
- {
- apr_finfo_t finfo;
- if (! (status = apr_stat(&finfo, filename, APR_FINFO_MIN, pool)))
- res_initial_len = (apr_size_t)finfo.size;
+ /* In some cases we get size 0 and no error for non files,
+ so we also check for the name. (= cached in apr_file_t) */
+ if (! apr_file_info_get(&finfo, APR_FINFO_SIZE | APR_FINFO_NAME, file)
+ && finfo.name != NULL)
+ {
+ /* we've got the file length. Now, read it in one go. */
+ svn_boolean_t eof;
+ res_initial_len = (apr_size_t)finfo.size;
+ res = svn_stringbuf_create_ensure(res_initial_len, pool);
+ SVN_ERR(svn_io_file_read_full2(file, res->data,
+ res_initial_len, &res->len,
+ &eof, pool));
+ res->data[res->len] = 0;
+
+ *result = res;
+ return SVN_NO_ERROR;
}
}
-
/* XXX: We should check the incoming data for being of type binary. */
-
+ buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
res = svn_stringbuf_create_ensure(res_initial_len, pool);
/* apr_file_read will not return data and eof in the same call. So this loop
@@ -2197,7 +2378,7 @@ stringbuf_from_aprfile(svn_stringbuf_t *
/* Having read all the data we *expect* EOF */
if (err && !APR_STATUS_IS_EOF(err->apr_err))
- return err;
+ return svn_error_trace(err);
svn_error_clear(err);
*result = res;
@@ -2795,10 +2976,23 @@ svn_io_wait_for_cmd(apr_proc_t *cmd_proc
if (exitwhy)
*exitwhy = exitwhy_val;
+ else if (APR_PROC_CHECK_SIGNALED(exitwhy_val)
+ && APR_PROC_CHECK_CORE_DUMP(exitwhy_val))
+ return svn_error_createf
+ (SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ _("Process '%s' failed (signal %d, core dumped)"),
+ cmd, exitcode_val);
+ else if (APR_PROC_CHECK_SIGNALED(exitwhy_val))
+ return svn_error_createf
+ (SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ _("Process '%s' failed (signal %d)"),
+ cmd, exitcode_val);
else if (! APR_PROC_CHECK_EXIT(exitwhy_val))
+ /* Don't really know what happened here. */
return svn_error_createf
(SVN_ERR_EXTERNAL_PROGRAM, NULL,
- _("Process '%s' failed (exitwhy %d)"), cmd, exitwhy_val);
+ _("Process '%s' failed (exitwhy %d, exitcode %d)"),
+ cmd, exitwhy_val, exitcode_val);
if (exitcode)
*exitcode = exitcode_val;
@@ -3293,7 +3487,7 @@ do_io_file_wrapper_cleanup(apr_file_t *f
/* ### Issue #3014: Return a specific error for broken pipes,
* ### with a single element in the error chain. */
- if (APR_STATUS_IS_EPIPE(status))
+ if (SVN__APR_STATUS_IS_EPIPE(status))
return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
if (name)
@@ -3396,6 +3590,101 @@ svn_io_file_seek(apr_file_t *file, apr_s
pool);
}
+svn_error_t *
+svn_io_file_aligned_seek(apr_file_t *file,
+ apr_off_t block_size,
+ apr_off_t *buffer_start,
+ apr_off_t offset,
+ apr_pool_t *pool)
+{
+ const apr_size_t apr_default_buffer_size = 4096;
+ apr_size_t file_buffer_size = apr_default_buffer_size;
+ apr_off_t desired_offset = 0;
+ apr_off_t current = 0;
+ apr_off_t aligned_offset = 0;
+ svn_boolean_t fill_buffer = FALSE;
+
+ /* paranoia check: huge blocks on 32 bit machines may cause overflows */
+ SVN_ERR_ASSERT(block_size == (apr_size_t)block_size);
+
+ /* default for invalid block sizes */
+ if (block_size == 0)
+ block_size = apr_default_buffer_size;
+
+ /* on old APRs, we are simply stuck with 4k blocks */
+#if APR_VERSION_AT_LEAST(1,3,0)
+ file_buffer_size = apr_file_buffer_size_get(file);
+
+ /* don't try to set a buffer size for non-buffered files! */
+ if (file_buffer_size == 0)
+ {
+ aligned_offset = offset;
+ }
+ else if (file_buffer_size != (apr_size_t)block_size)
+ {
+ /* FILE has the wrong buffer size. correct it */
+ char *buffer;
+ file_buffer_size = (apr_size_t)block_size;
+ buffer = apr_palloc(apr_file_pool_get(file), file_buffer_size);
+ apr_file_buffer_set(file, buffer, file_buffer_size);
+
+ /* seek to the start of the block and cause APR to read 1 block */
+ aligned_offset = offset - (offset % block_size);
+ fill_buffer = TRUE;
+ }
+#endif
+ {
+ aligned_offset = offset - (offset % file_buffer_size);
+
+ /* We have no way to determine the block start of an APR file.
+ Furthermore, we don't want to throw away the current buffer
+ contents. Thus, we re-align the buffer only if the CURRENT
+ offset definitely lies outside the desired, aligned buffer.
+ This covers the typical case of linear reads getting very
+ close to OFFSET but reading the previous / following block.
+
+ Note that ALIGNED_OFFSET may still be within the current
+ buffer and no I/O will actually happen in the FILL_BUFFER
+ section below.
+ */
+ SVN_ERR(svn_io_file_seek(file, SEEK_CUR, ¤t, pool));
+ fill_buffer = aligned_offset + file_buffer_size <= current
+ || current <= aligned_offset;
+ }
+
+ if (fill_buffer)
+ {
+ char dummy;
+ apr_status_t status;
+
+ /* seek to the start of the block and cause APR to read 1 block */
+ SVN_ERR(svn_io_file_seek(file, SEEK_SET, &aligned_offset, pool));
+ status = apr_file_getc(&dummy, file);
+
+ /* read may fail if we seek to or behind EOF. That's ok then. */
+ if (status != APR_SUCCESS && !APR_STATUS_IS_EOF(status))
+ return do_io_file_wrapper_cleanup(file, status,
+ N_("Can't read file '%s'"),
+ N_("Can't read stream"),
+ pool);
+ }
+
+ /* finally, seek to the OFFSET the caller wants */
+ desired_offset = offset;
+ SVN_ERR(svn_io_file_seek(file, SEEK_SET, &offset, pool));
+ if (desired_offset != offset)
+ return do_io_file_wrapper_cleanup(file, APR_EOF,
+ N_("Can't seek in file '%s'"),
+ N_("Can't seek in stream"),
+ pool);
+
+ /* return the buffer start that we (probably) enforced */
+ if (buffer_start)
+ *buffer_start = aligned_offset;
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_io_file_write(apr_file_t *file, const void *buf,
@@ -3408,6 +3697,16 @@ svn_io_file_write(apr_file_t *file, cons
pool));
}
+svn_error_t *
+svn_io_file_flush(apr_file_t *file,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(do_io_file_wrapper_cleanup(
+ file, apr_file_flush(file),
+ N_("Can't flush file '%s'"),
+ N_("Can't flush stream"),
+ scratch_pool));
+}
svn_error_t *
svn_io_file_write_full(apr_file_t *file, const void *buf,
@@ -3472,23 +3771,76 @@ svn_io_write_unique(const char **tmp_pat
err = svn_io_file_write_full(new_file, buf, nbytes, NULL, pool);
- /* ### BH: Windows doesn't have the race condition between the write and the
- ### rename that other operating systems might have. So allow windows
- ### to decide when it wants to perform the disk synchronization using
- ### the normal file locking and journaling filesystem rules.
-
- ### Note that this function doesn't handle the rename, so we aren't even
- ### sure that we really have to sync. */
-#ifndef WIN32
- if (!err && nbytes > 0)
- err = svn_io_file_flush_to_disk(new_file, pool);
-#endif
+ if (!err)
+ {
+ /* svn_io_file_flush_to_disk() can be very expensive, so use the
+ cheaper standard flush if the file is created as temporary file
+ anyway */
+ if (delete_when == svn_io_file_del_none)
+ err = svn_io_file_flush_to_disk(new_file, pool);
+ else
+ err = svn_io_file_flush(new_file, pool);
+ }
return svn_error_trace(
svn_error_compose_create(err,
svn_io_file_close(new_file, pool)));
}
+svn_error_t *
+svn_io_write_atomic(const char *final_path,
+ const void *buf,
+ apr_size_t nbytes,
+ const char *copy_perms_path,
+ apr_pool_t *scratch_pool)
+{
+ apr_file_t *tmp_file;
+ const char *tmp_path;
+ svn_error_t *err;
+ const char *dirname = svn_dirent_dirname(final_path, scratch_pool);
+
+ SVN_ERR(svn_io_open_unique_file3(&tmp_file, &tmp_path, dirname,
+ svn_io_file_del_none,
+ scratch_pool, scratch_pool));
+
+ err = svn_io_file_write_full(tmp_file, buf, nbytes, NULL, scratch_pool);
+
+ if (!err)
+ err = svn_io_file_flush_to_disk(tmp_file, scratch_pool);
+
+ err = svn_error_compose_create(err,
+ svn_io_file_close(tmp_file, scratch_pool));
+
+ if (!err && copy_perms_path)
+ err = svn_io_copy_perms(copy_perms_path, tmp_path, scratch_pool);
+
+ if (err)
+ {
+ return svn_error_compose_create(err,
+ svn_io_remove_file2(tmp_path, FALSE,
+ scratch_pool));
+ }
+
+ SVN_ERR(svn_io_file_rename(tmp_path, final_path, scratch_pool));
+
+#ifdef __linux__
+ {
+ /* Linux has the unusual feature that fsync() on a file is not
+ enough to ensure that a file's directory entries have been
+ flushed to disk; you have to fsync the directory as well.
+ On other operating systems, we'd only be asking for trouble
+ by trying to open and fsync a directory. */
+ apr_file_t *file;
+
+ SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
+ scratch_pool));
+ SVN_ERR(svn_io_file_flush_to_disk(file, scratch_pool));
+ SVN_ERR(svn_io_file_close(file, scratch_pool));
+ }
+#endif
+
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_io_file_trunc(apr_file_t *file, apr_off_t offset, apr_pool_t *pool)
@@ -3529,6 +3881,9 @@ svn_io_read_length_line(apr_file_t *file
apr_size_t bytes_read = 0;
char *eol;
+ if (to_read == 0)
+ break;
+
/* read data block (or just a part of it) */
SVN_ERR(svn_io_file_read_full2(file, buf, to_read,
&bytes_read, &eof, pool));
Modified: subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c Tue Oct 15 08:52:06 2013
@@ -23,6 +23,7 @@
#include <assert.h>
#include <ctype.h>
+#include "svn_private_config.h"
#include "svn_path.h"
#include "svn_types.h"
#include "svn_ctype.h"
@@ -36,7 +37,6 @@
#include "private/svn_mergeinfo_private.h"
#include "private/svn_string_private.h"
#include "private/svn_subr_private.h"
-#include "svn_private_config.h"
#include "svn_hash.h"
#include "private/svn_dep_compat.h"
@@ -611,6 +611,23 @@ svn_rangelist__parse(svn_rangelist_t **r
return SVN_NO_ERROR;
}
+/* Return TRUE, if all ranges in RANGELIST are in ascending order and do
+ * not overlap. If this returns FALSE, you probaly want to qsort() the
+ * ranges and then call svn_rangelist__combine_adjacent_ranges().
+ */
+static svn_boolean_t
+is_rangelist_normalized(svn_rangelist_t *rangelist)
+{
+ int i;
+ svn_merge_range_t **ranges = (svn_merge_range_t **)rangelist->elts;
+
+ for (i = 0; i < rangelist->nelts-1; ++i)
+ if (ranges[i]->end >= ranges[i+1]->start)
+ return FALSE;
+
+ return TRUE;
+}
+
svn_error_t *
svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
apr_pool_t *scratch_pool)
@@ -692,9 +709,11 @@ parse_revision_line(const char **input,
if (*input != end)
*input = *input + 1;
- /* Sort the rangelist, combine adjacent ranges into single ranges,
- and make sure there are no overlapping ranges. */
- if (rangelist->nelts > 1)
+ /* Sort the rangelist, combine adjacent ranges into single ranges, and
+ make sure there are no overlapping ranges. Luckily, most data in
+ svn:mergeinfo will already be in normalized form and we can skip this.
+ */
+ if (! is_rangelist_normalized(rangelist))
{
qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
svn_sort_compare_ranges);
@@ -2223,16 +2242,19 @@ svn_rangelist_dup(const svn_rangelist_t
/* allocate target range buffer with a single operation */
svn_merge_range_t *copy = apr_palloc(pool, sizeof(*copy) * rangelist->nelts);
+
+ /* for efficiency, directly address source and target reference buffers */
+ svn_merge_range_t **source = (svn_merge_range_t **)(rangelist->elts);
+ svn_merge_range_t **target = (svn_merge_range_t **)(new_rl->elts);
int i;
- /* fill it iteratively and link it into the range list */
+ /* copy ranges iteratively and link them into the target range list */
for (i = 0; i < rangelist->nelts; i++)
{
- memcpy(copy + i,
- APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
- sizeof(*copy));
- APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) = copy + i;
+ copy[i] = *source[i];
+ target[i] = ©[i];
}
+ new_rl->nelts = rangelist->nelts;
return new_rl;
}
Modified: subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c Tue Oct 15 08:52:06 2013
@@ -251,6 +251,7 @@ struct svn_atomic_namespace__t
*/
static svn_mutex__t *thread_mutex = NULL;
+#if APR_HAS_MMAP
/* Initialization flag for the above used by svn_atomic__init_once.
*/
static volatile svn_atomic_t mutex_initialized = FALSE;
@@ -266,6 +267,7 @@ init_thread_mutex(void *baton, apr_pool_
return svn_mutex__init(&thread_mutex, USE_THREAD_MUTEX, global_pool);
}
+#endif /* APR_HAS_MMAP */
/* Utility that acquires our global mutex and converts error types.
*/
@@ -297,6 +299,7 @@ unlock(struct mutex_t *mutex, svn_error_
unlock_err));
}
+#if APR_HAS_MMAP
/* The last user to close a particular namespace should also remove the
* lock file. Failure to do so, however, does not affect further uses
* of the same namespace.
@@ -318,6 +321,7 @@ delete_lock_file(void *arg)
return status;
}
+#endif /* APR_HAS_MMAP */
/* Validate the ATOMIC parameter, i.e it's address. Correct code will
* never need this but if someone should accidentally to use a NULL or
@@ -351,7 +355,11 @@ return_atomic(svn_named_atomic__t **atom
svn_boolean_t
svn_named_atomic__is_supported(void)
{
-#ifdef _WIN32
+#if !APR_HAS_MMAP
+ return FALSE;
+#elif !defined(_WIN32)
+ return TRUE;
+#else
static svn_tristate_t result = svn_tristate_unknown;
if (result == svn_tristate_unknown)
@@ -373,9 +381,7 @@ svn_named_atomic__is_supported(void)
}
return result == svn_tristate_true;
-#else
- return TRUE;
-#endif
+#endif /* _WIN32 */
}
svn_boolean_t
@@ -389,6 +395,9 @@ svn_atomic_namespace__create(svn_atomic_
const char *name,
apr_pool_t *result_pool)
{
+#if !APR_HAS_MMAP
+ return svn_error_create(APR_ENOTIMPL, NULL, NULL);
+#else
apr_status_t apr_err;
svn_error_t *err;
apr_file_t *file;
@@ -489,6 +498,7 @@ svn_atomic_namespace__create(svn_atomic_
/* Unlock to allow other processes may access the shared memory as well.
*/
return unlock(&new_ns->mutex, err);
+#endif /* APR_HAS_MMAP */
}
svn_error_t *
Modified: subversion/branches/cache-server/subversion/libsvn_subr/nls.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/nls.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/nls.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/nls.c Tue Oct 15 08:52:06 2013
@@ -56,10 +56,9 @@ svn_nls_init(void)
char* utf8_path;
const char* internal_path;
apr_pool_t* pool;
- apr_status_t apr_err;
apr_size_t inwords, outbytes, outlength;
- apr_pool_create(&pool, 0);
+ pool = svn_pool_create(0);
/* get exe name - our locale info will be in '../share/locale' */
inwords = GetModuleFileNameW(0, ucs2_path,
sizeof(ucs2_path) / sizeof(ucs2_path[0]));
@@ -99,10 +98,10 @@ svn_nls_init(void)
if (outbytes == 0)
{
- err = svn_error_createf(apr_err, NULL,
- _("Can't convert module path "
- "to UTF-8 from UCS-2: '%s'"),
- ucs2_path);
+ err = svn_error_wrap_apr(apr_get_os_error(),
+ _("Can't convert module path "
+ "to UTF-8 from UCS-2: '%s'"),
+ ucs2_path);
}
else
{
Modified: subversion/branches/cache-server/subversion/libsvn_subr/opt.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/opt.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/opt.c Tue Oct 15 08:52:06 2013
@@ -34,6 +34,7 @@
#include <apr_lib.h>
#include <apr_file_info.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_cmdline.h"
#include "svn_version.h"
@@ -50,7 +51,6 @@
#include "private/svn_opt_private.h"
#include "opt.h"
-#include "svn_private_config.h"
/*** Code. ***/
Modified: subversion/branches/cache-server/subversion/libsvn_subr/path.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/path.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/path.c Tue Oct 15 08:52:06 2013
@@ -1164,11 +1164,8 @@ svn_path_cstring_to_utf8(const char **pa
}
-/* Return a copy of PATH, allocated from POOL, for which control
- characters have been escaped using the form \NNN (where NNN is the
- octal representation of the byte's ordinal value). */
-static const char *
-illegal_path_escape(const char *path, apr_pool_t *pool)
+const char *
+svn_path_illegal_path_escape(const char *path, apr_pool_t *pool)
{
svn_stringbuf_t *retstr;
apr_size_t i, copied = 0;
@@ -1194,7 +1191,7 @@ illegal_path_escape(const char *path, ap
i - copied);
/* Make sure buffer is big enough for '\' 'N' 'N' 'N' (and NUL) */
- svn_stringbuf_ensure(retstr, retstr->len + 4);
+ svn_stringbuf_ensure(retstr, retstr->len + 5);
/*### The backslash separator doesn't work too great with Windows,
but it's what we'll use for consistency with invalid utf8
formatting (until someone has a better idea) */
@@ -1228,11 +1225,11 @@ svn_path_check_valid(const char *path, a
{
if (svn_ctype_iscntrl(*c))
{
- return svn_error_createf
- (SVN_ERR_FS_PATH_SYNTAX, NULL,
+ return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
_("Invalid control character '0x%02x' in path '%s'"),
(unsigned char)*c,
- illegal_path_escape(svn_dirent_local_style(path, pool), pool));
+ svn_path_illegal_path_escape(svn_dirent_local_style(path, pool),
+ pool));
}
}
Modified: subversion/branches/cache-server/subversion/libsvn_subr/pool.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/pool.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/pool.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/pool.c Tue Oct 15 08:52:06 2013
@@ -51,7 +51,7 @@ abort_on_pool_failure(int retcode)
{
/* Don't translate this string! It requires memory allocation to do so!
And we don't have any of it... */
- printf("Out of memory - terminating application.\n");
+ printf("libsvn: Out of memory - terminating application.\n");
abort();
return 0; /* not reached */
}
Modified: subversion/branches/cache-server/subversion/libsvn_subr/prompt.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/prompt.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/prompt.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/prompt.c Tue Oct 15 08:52:06 2013
@@ -236,7 +236,6 @@ terminal_puts(const char *string, termin
apr_pool_t *pool)
{
svn_error_t *err;
- apr_status_t status;
const char *converted;
err = svn_cmdline_cstring_from_utf8(&converted, string, pool);
@@ -255,13 +254,10 @@ terminal_puts(const char *string, termin
}
#endif
- status = apr_file_write_full(terminal->outfd, converted,
- strlen(converted), NULL);
- if (!status)
- status = apr_file_flush(terminal->outfd);
- if (status)
- return svn_error_wrap_apr(status, _("Can't write to terminal"));
- return SVN_NO_ERROR;
+ SVN_ERR(svn_io_file_write_full(terminal->outfd, converted,
+ strlen(converted), NULL, pool));
+
+ return svn_error_trace(svn_io_file_flush(terminal->outfd, pool));
}
/* These codes can be returned from terminal_getc instead of a character. */
Modified: subversion/branches/cache-server/subversion/libsvn_subr/properties.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/properties.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/properties.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/properties.c Tue Oct 15 08:52:06 2013
@@ -27,6 +27,8 @@
#include <apr_hash.h>
#include <apr_tables.h>
#include <string.h> /* for strncmp() */
+
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_string.h"
#include "svn_props.h"
Modified: subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c Tue Oct 15 08:52:06 2013
@@ -28,6 +28,8 @@
/*** Includes. ***/
#include <apr_pools.h>
+
+#include "svn_private_config.h"
#include "svn_auth.h"
#include "svn_dirent_uri.h"
#include "svn_hash.h"
@@ -39,8 +41,6 @@
#include "private/svn_auth_private.h"
-#include "svn_private_config.h"
-
#include "auth.h"
/*-----------------------------------------------------------------------*/
Modified: subversion/branches/cache-server/subversion/libsvn_subr/sorts.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/sorts.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/sorts.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/sorts.c Tue Oct 15 08:52:06 2013
@@ -28,6 +28,8 @@
#include <apr_tables.h>
#include <stdlib.h> /* for qsort() */
#include <assert.h>
+
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_path.h"
#include "svn_sorts.h"
@@ -307,3 +309,148 @@ svn_sort__array_reverse(apr_array_header
}
}
}
+
+/* Our priority queue data structure:
+ * Simply remember the constructor parameters.
+ */
+struct svn_priority_queue__t
+{
+ /* the queue elements, ordered as a heap according to COMPARE_FUNC */
+ apr_array_header_t *elements;
+
+ /* predicate used to order the heap */
+ int (*compare_func)(const void *, const void *);
+};
+
+/* Return TRUE, if heap element number LHS in QUEUE is smaller than element
+ * number RHS according to QUEUE->COMPARE_FUNC
+ */
+static int
+heap_is_less(svn_priority_queue__t *queue,
+ apr_size_t lhs,
+ apr_size_t rhs)
+{
+ char *lhs_value = queue->elements->elts + lhs * queue->elements->elt_size;
+ char *rhs_value = queue->elements->elts + rhs * queue->elements->elt_size;
+
+ assert(lhs < queue->elements->nelts);
+ assert(rhs < queue->elements->nelts);
+ return queue->compare_func((void *)lhs_value, (void *)rhs_value) < 0;
+}
+
+/* Exchange elements number LHS and RHS in QUEUE.
+ */
+static void
+heap_swap(svn_priority_queue__t *queue,
+ apr_size_t lhs,
+ apr_size_t rhs)
+{
+ int i;
+ char *lhs_value = queue->elements->elts + lhs * queue->elements->elt_size;
+ char *rhs_value = queue->elements->elts + rhs * queue->elements->elt_size;
+
+ for (i = 0; i < queue->elements->elt_size; ++i)
+ {
+ char temp = lhs_value[i];
+ lhs_value[i] = rhs_value[i];
+ rhs_value[i] = temp;
+ }
+}
+
+/* Move element number IDX to lower indexes until the heap criterion is
+ * fulfilled again.
+ */
+static void
+heap_bubble_down(svn_priority_queue__t *queue,
+ int idx)
+{
+ while (idx > 0 && heap_is_less(queue, idx, (idx - 1) / 2))
+ {
+ heap_swap(queue, idx, (idx - 1) / 2);
+ idx = (idx - 1) / 2;
+ }
+}
+
+/* Move element number IDX to higher indexes until the heap criterion is
+ * fulfilled again.
+ */
+static void
+heap_bubble_up(svn_priority_queue__t *queue,
+ int idx)
+{
+ while (2 * idx + 2 < queue->elements->nelts)
+ {
+ int child = heap_is_less(queue, 2 * idx + 1, 2 * idx + 2)
+ ? 2 * idx + 1
+ : 2 * idx + 2;
+
+ if (heap_is_less(queue, idx, child))
+ return;
+
+ heap_swap(queue, idx, child);
+ idx = child;
+ }
+
+ if ( 2 * idx + 1 < queue->elements->nelts
+ && heap_is_less(queue, 2 * idx + 1, idx))
+ heap_swap(queue, 2 * idx + 1, idx);
+}
+
+svn_priority_queue__t *
+svn_priority_queue__create(apr_array_header_t *elements,
+ int (*compare_func)(const void *, const void *))
+{
+ int i;
+
+ svn_priority_queue__t *queue = apr_pcalloc(elements->pool, sizeof(*queue));
+ queue->elements = elements;
+ queue->compare_func = compare_func;
+
+ for (i = elements->nelts / 2; i >= 0; --i)
+ heap_bubble_up(queue, i);
+
+ return queue;
+}
+
+apr_size_t
+svn_priority_queue__size(svn_priority_queue__t *queue)
+{
+ return queue->elements->nelts;
+}
+
+void *
+svn_priority_queue__peek(svn_priority_queue__t *queue)
+{
+ return queue->elements->nelts ? queue->elements->elts : NULL;
+}
+
+void
+svn_priority_queue__update(svn_priority_queue__t *queue)
+{
+ heap_bubble_up(queue, 0);
+}
+
+void
+svn_priority_queue__pop(svn_priority_queue__t *queue)
+{
+ if (queue->elements->nelts)
+ {
+ memcpy(queue->elements->elts,
+ queue->elements->elts + (queue->elements->nelts - 1)
+ * queue->elements->elt_size,
+ queue->elements->elt_size);
+ --queue->elements->nelts;
+ heap_bubble_up(queue, 0);
+ }
+}
+
+void
+svn_priority_queue__push(svn_priority_queue__t *queue,
+ const void *element)
+{
+ /* we cannot duplicate elements due to potential array re-allocs */
+ assert(element && element != queue->elements->elts);
+
+ memcpy(apr_array_push(queue->elements), element, queue->elements->elt_size);
+ heap_bubble_down(queue, queue->elements->nelts - 1);
+}
Modified: subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c Tue Oct 15 08:52:06 2013
@@ -73,12 +73,26 @@ struct svn_spillbuf_t {
/* How much content remains in SPILL. */
svn_filesize_t spill_size;
+
+ /* When false, do not delete the spill file when it is closed. */
+ svn_boolean_t delete_on_close;
+
+ /* When true, and the amount of data written to the spillbuf is
+ larger than MAXSIZE, all spillbuf contents will be written to the
+ spill file. */
+ svn_boolean_t spill_all_contents;
+
+ /* The directory in which the spill file is created. */
+ const char *dirpath;
+
+ /* The name of the temporary spill file. */
+ const char *filename;
};
struct svn_spillbuf_reader_t {
/* Embed the spill-buffer within the reader. */
- struct svn_spillbuf_t buf;
+ struct svn_spillbuf_t *buf;
/* When we read content from the underlying spillbuf, these fields store
the ptr/len pair. The ptr will be incremented as we "read" out of this
@@ -99,28 +113,86 @@ struct svn_spillbuf_reader_t {
};
+/* Extended spillbuf initialization. */
+static void
+init_spillbuf_extended(svn_spillbuf_t *buf,
+ apr_size_t blocksize,
+ apr_size_t maxsize,
+ svn_boolean_t delete_on_close,
+ svn_boolean_t spill_all_contents,
+ const char *dirpath,
+ apr_pool_t *result_pool)
+{
+ buf->pool = result_pool;
+ buf->blocksize = blocksize;
+ buf->maxsize = maxsize;
+ buf->delete_on_close = delete_on_close;
+ buf->spill_all_contents = spill_all_contents;
+ buf->dirpath = dirpath;
+}
+
+/* Common constructor for initializing spillbufs.
+ Used by svn_spillbuf__create, svn_spilbuff__reader_create. */
+static void
+init_spillbuf(svn_spillbuf_t *buf,
+ apr_size_t blocksize,
+ apr_size_t maxsize,
+ apr_pool_t *result_pool)
+{
+ init_spillbuf_extended(buf, blocksize, maxsize,
+ TRUE, FALSE, NULL,
+ result_pool);
+}
+
svn_spillbuf_t *
svn_spillbuf__create(apr_size_t blocksize,
apr_size_t maxsize,
apr_pool_t *result_pool)
{
svn_spillbuf_t *buf = apr_pcalloc(result_pool, sizeof(*buf));
+ init_spillbuf(buf, blocksize, maxsize, result_pool);
+ return buf;
+}
- buf->pool = result_pool;
- buf->blocksize = blocksize;
- buf->maxsize = maxsize;
- /* Note: changes here should also go into svn_spillbuf__reader_create() */
+svn_spillbuf_t *
+svn_spillbuf__create_extended(apr_size_t blocksize,
+ apr_size_t maxsize,
+ svn_boolean_t delete_on_close,
+ svn_boolean_t spill_all_contents,
+ const char *dirpath,
+ apr_pool_t *result_pool)
+{
+ svn_spillbuf_t *buf = apr_pcalloc(result_pool, sizeof(*buf));
+ init_spillbuf_extended(buf, blocksize, maxsize,
+ delete_on_close, spill_all_contents, dirpath,
+ result_pool);
return buf;
}
-
svn_filesize_t
svn_spillbuf__get_size(const svn_spillbuf_t *buf)
{
return buf->memory_size + buf->spill_size;
}
+svn_filesize_t
+svn_spillbuf__get_memory_size(const svn_spillbuf_t *buf)
+{
+ return buf->memory_size;
+}
+
+const char *
+svn_spillbuf__get_filename(const svn_spillbuf_t *buf)
+{
+ return buf->filename;
+}
+
+apr_file_t *
+svn_spillbuf__get_file(const svn_spillbuf_t *buf)
+{
+ return buf->spill;
+}
/* Get a memblock from the spill-buffer. It will be the block that we
passed out for reading, come from the free list, or allocated. */
@@ -173,10 +245,32 @@ svn_spillbuf__write(svn_spillbuf_t *buf,
&& (buf->memory_size + len) > buf->maxsize)
{
SVN_ERR(svn_io_open_unique_file3(&buf->spill,
- NULL /* temp_path */,
- NULL /* dirpath */,
- svn_io_file_del_on_close,
+ &buf->filename,
+ buf->dirpath,
+ (buf->delete_on_close
+ ? svn_io_file_del_on_close
+ : svn_io_file_del_none),
buf->pool, scratch_pool));
+
+ /* Optionally write the memory contents into the file. */
+ if (buf->spill_all_contents)
+ {
+ mem = buf->head;
+ while (mem != NULL)
+ {
+ SVN_ERR(svn_io_file_write_full(buf->spill, mem->data, mem->size,
+ NULL, scratch_pool));
+ mem = mem->next;
+ }
+
+ /* Adjust the start offset for reading from the spill file.
+
+ ### FIXME: Instead, we should simply discard the memory
+ buffers; but currently some tests expect to read data in
+ the same chunk sizes as were written, so we'll leave this
+ change for later.*/
+ buf->spill_start = buf->memory_size;
+ }
}
/* Once a spill file has been constructed, then we need to put all
@@ -440,16 +534,10 @@ svn_spillbuf__reader_create(apr_size_t b
apr_pool_t *result_pool)
{
svn_spillbuf_reader_t *sbr = apr_pcalloc(result_pool, sizeof(*sbr));
-
- /* See svn_spillbuf__create() */
- sbr->buf.pool = result_pool;
- sbr->buf.blocksize = blocksize;
- sbr->buf.maxsize = maxsize;
-
+ sbr->buf = svn_spillbuf__create(blocksize, maxsize, result_pool);
return sbr;
}
-
svn_error_t *
svn_spillbuf__reader_read(apr_size_t *amt,
svn_spillbuf_reader_t *reader,
@@ -488,7 +576,7 @@ svn_spillbuf__reader_read(apr_size_t *am
if (reader->sb_len == 0)
{
SVN_ERR(svn_spillbuf__read(&reader->sb_ptr, &reader->sb_len,
- &reader->buf,
+ reader->buf,
scratch_pool));
/* We've run out of content, so return with whatever has
@@ -547,7 +635,8 @@ svn_spillbuf__reader_write(svn_spillbuf_
if (reader->sb_len > 0)
{
if (reader->save_ptr == NULL)
- reader->save_ptr = apr_palloc(reader->buf.pool, reader->buf.blocksize);
+ reader->save_ptr = apr_palloc(reader->buf->pool,
+ reader->buf->blocksize);
memcpy(reader->save_ptr, reader->sb_ptr, reader->sb_len);
reader->save_len = reader->sb_len;
@@ -557,7 +646,7 @@ svn_spillbuf__reader_write(svn_spillbuf_
reader->sb_len = 0;
}
- return svn_error_trace(svn_spillbuf__write(&reader->buf, data, len,
+ return svn_error_trace(svn_spillbuf__write(reader->buf, data, len,
scratch_pool));
}
@@ -596,14 +685,14 @@ write_handler_spillbuf(void *baton, cons
svn_stream_t *
-svn_stream__from_spillbuf(apr_size_t blocksize,
- apr_size_t maxsize,
+svn_stream__from_spillbuf(svn_spillbuf_t *buf,
apr_pool_t *result_pool)
{
svn_stream_t *stream;
struct spillbuf_baton *sb = apr_palloc(result_pool, sizeof(*sb));
- sb->reader = svn_spillbuf__reader_create(blocksize, maxsize, result_pool);
+ sb->reader = apr_pcalloc(result_pool, sizeof(*sb->reader));
+ sb->reader->buf = buf;
sb->scratch_pool = svn_pool_create(result_pool);
stream = svn_stream_create(sb, result_pool);
Modified: subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c Tue Oct 15 08:52:06 2013
@@ -38,6 +38,11 @@
#include "private/svn_skel.h"
#include "private/svn_token.h"
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+#include "private/svn_utf_private.h"
+#include "private/svn_string_private.h"
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
#ifdef SQLITE3_DEBUG
#include "private/svn_debug.h"
#endif
@@ -60,6 +65,13 @@ extern int (*const svn_sqlite3__api_conf
#error SQLite is too old -- version 3.7.12 is the minimum required version
#endif
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+/* Limit the length of a GLOB or LIKE pattern. */
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
+#endif
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
const char *
svn_sqlite__compiled_version(void)
{
@@ -104,6 +116,13 @@ struct svn_sqlite__db_t
int nbr_statements;
svn_sqlite__stmt_t **prepared_stmts;
apr_pool_t *state_pool;
+
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+ /* Buffers for SQLite extensoins. */
+ svn_membuf_t sqlext_buf1;
+ svn_membuf_t sqlext_buf2;
+ svn_membuf_t sqlext_buf3;
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
};
struct svn_sqlite__stmt_t
@@ -140,9 +159,9 @@ struct svn_sqlite__value_t
int sqlite_err__temp = (x); \
if (sqlite_err__temp != SQLITE_OK) \
return svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
- NULL, "sqlite: %s (S%d)", \
- sqlite3_errmsg((db)->db3), \
- sqlite_err__temp); \
+ NULL, "sqlite[S%d]: %s", \
+ sqlite_err__temp, \
+ sqlite3_errmsg((db)->db3)); \
} while (0)
#define SQLITE_ERR_MSG(x, msg) do \
@@ -150,8 +169,8 @@ struct svn_sqlite__value_t
int sqlite_err__temp = (x); \
if (sqlite_err__temp != SQLITE_OK) \
return svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
- NULL, "sqlite: %s (S%d)", (msg), \
- sqlite_err__temp); \
+ NULL, "sqlite[S%d]: %s", \
+ sqlite_err__temp, msg); \
} while (0)
@@ -173,9 +192,9 @@ exec_sql2(svn_sqlite__db_t *db, const ch
if (sqlite_err != SQLITE_OK && sqlite_err != ignored_err)
{
svn_error_t *err = svn_error_createf(SQLITE_ERROR_CODE(sqlite_err), NULL,
- _("sqlite: %s (S%d),"
+ _("sqlite[S%d]: %s,"
" executing statement '%s'"),
- err_msg, sqlite_err, sql);
+ sqlite_err, err_msg, sql);
sqlite3_free(err_msg);
return err;
}
@@ -292,8 +311,8 @@ svn_sqlite__step(svn_boolean_t *got_row,
svn_error_t *err1, *err2;
err1 = svn_error_createf(SQLITE_ERROR_CODE(sqlite_result), NULL,
- "sqlite: %s (S%d)",
- sqlite3_errmsg(stmt->db->db3), sqlite_result);
+ "sqlite[S%d]: %s",
+ sqlite_result, sqlite3_errmsg(stmt->db->db3));
err2 = svn_sqlite__reset(stmt);
return svn_error_compose_create(err1, err2);
}
@@ -744,7 +763,7 @@ init_sqlite(void *baton, apr_pool_t *poo
int err = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
if (err != SQLITE_OK && err != SQLITE_MISUSE)
return svn_error_createf(SQLITE_ERROR_CODE(err), NULL,
- _("Could not configure SQLite (S%d)"), err);
+ _("Could not configure SQLite [S%d]"), err);
}
SQLITE_ERR_MSG(sqlite3_initialize(), _("Could not initialize SQLite"));
@@ -873,6 +892,99 @@ close_apr(void *data)
return APR_SUCCESS;
}
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+/* Unicode normalizing collation for WC paths */
+static int
+collate_ucs_nfd(void *baton,
+ int len1, const void *key1,
+ int len2, const void *key2)
+{
+ svn_sqlite__db_t *db = baton;
+ int result;
+
+ if (svn_utf__normcmp(key1, len1, key2, len2,
+ &db->sqlext_buf1, &db->sqlext_buf2, &result))
+ {
+ /* There is really nothing we can do here if an error occurs
+ during Unicode normalizetion, and attempting to recover could
+ result in the wc.db index being corrupted. Presumably this
+ can only happen if the index already contains invalid UTF-8
+ strings, which should never happen in any case ... */
+ SVN_ERR_MALFUNCTION_NO_RETURN();
+ }
+
+ return result;
+}
+
+static void
+glob_like_ucs_nfd_common(sqlite3_context *context,
+ int argc, sqlite3_value **argv,
+ svn_boolean_t sql_like)
+{
+ svn_sqlite__db_t *const db = sqlite3_user_data(context);
+
+ const char *const pattern = (void*)sqlite3_value_text(argv[0]);
+ const apr_size_t pattern_len = sqlite3_value_bytes(argv[0]);
+ const char *const string = (void*)sqlite3_value_text(argv[1]);
+ const apr_size_t string_len = sqlite3_value_bytes(argv[1]);
+
+ const char *escape = NULL;
+ apr_size_t escape_len = 0;
+
+ svn_boolean_t match;
+ svn_error_t *err;
+
+ if (pattern_len > SQLITE_MAX_LIKE_PATTERN_LENGTH)
+ {
+ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
+ return;
+ }
+
+ if (argc == 3 && sql_like)
+ {
+ escape = (void*)sqlite3_value_text(argv[2]);
+ escape_len = sqlite3_value_bytes(argv[2]);
+ }
+
+ if (pattern && string)
+ {
+ err = svn_utf__glob(pattern, pattern_len, string, string_len,
+ escape, escape_len, sql_like,
+ &db->sqlext_buf1, &db->sqlext_buf2, &db->sqlext_buf3,
+ &match);
+
+ if (err)
+ {
+ const char *errmsg;
+ svn_membuf__ensure(&db->sqlext_buf1, 512);
+ errmsg = svn_err_best_message(err,
+ db->sqlext_buf1.data,
+ db->sqlext_buf1.size - 1);
+ svn_error_clear(err);
+ sqlite3_result_error(context, errmsg, -1);
+ return;
+ }
+
+ sqlite3_result_int(context, match);
+ }
+}
+
+/* Unicode normalizing implementation of GLOB */
+static void
+glob_ucs_nfd(sqlite3_context *context,
+ int argc, sqlite3_value **argv)
+{
+ glob_like_ucs_nfd_common(context, argc, argv, FALSE);
+}
+
+/* Unicode normalizing implementation of LIKE */
+static void
+like_ucs_nfd(sqlite3_context *context,
+ int argc, sqlite3_value **argv)
+{
+ glob_like_ucs_nfd_common(context, argc, argv, TRUE);
+}
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
svn_error_t *
svn_sqlite__open(svn_sqlite__db_t **db, const char *path,
@@ -887,6 +999,28 @@ svn_sqlite__open(svn_sqlite__db_t **db,
SVN_ERR(internal_open(&(*db)->db3, path, mode, scratch_pool));
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+ /* Create extension buffers with space for 200 UCS-4 characters. */
+ svn_membuf__create(&(*db)->sqlext_buf1, 800, result_pool);
+ svn_membuf__create(&(*db)->sqlext_buf2, 800, result_pool);
+ svn_membuf__create(&(*db)->sqlext_buf3, 800, result_pool);
+
+ /* Register collation and LIKE and GLOB operator replacements. */
+ SQLITE_ERR(sqlite3_create_collation((*db)->db3,
+ "svn-ucs-nfd", SQLITE_UTF8,
+ *db, collate_ucs_nfd),
+ *db);
+ SQLITE_ERR(sqlite3_create_function((*db)->db3, "glob", 2, SQLITE_UTF8,
+ *db, glob_ucs_nfd, NULL, NULL),
+ *db);
+ SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 2, SQLITE_UTF8,
+ *db, like_ucs_nfd, NULL, NULL),
+ *db);
+ SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 3, SQLITE_UTF8,
+ *db, like_ucs_nfd, NULL, NULL),
+ *db);
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
#ifdef SQLITE3_DEBUG
sqlite3_trace((*db)->db3, sqlite_tracer, (*db)->db3);
#endif
Modified: subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c Tue Oct 15 08:52:06 2013
@@ -39,6 +39,17 @@
# pragma GCC diagnostic ignored "-Wshorten-64-to-32"
# endif
# endif
+# ifdef __APPLE__
+# include <Availability.h>
+# if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+ /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and
+ on old systems (Leopard or older), it cannot be compiled
+ with -std=c89 because it uses inline. This is a work-around. */
+# define inline __inline__
+# include <libkern/OSAtomic.h>
+# undef inline
+# endif
+# endif
# include <sqlite3.c>
# if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
# pragma GCC diagnostic pop
Modified: subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c Tue Oct 15 08:52:06 2013
@@ -29,6 +29,8 @@
/*** Includes. ***/
#include <apr_pools.h>
+
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_auth.h"
#include "svn_error.h"
@@ -79,13 +81,12 @@ ssl_client_cert_file_first_credentials(v
}
-static const svn_auth_provider_t ssl_client_cert_file_provider =
- {
- SVN_AUTH_CRED_SSL_CLIENT_CERT,
- ssl_client_cert_file_first_credentials,
- NULL,
- NULL
- };
+static const svn_auth_provider_t ssl_client_cert_file_provider = {
+ SVN_AUTH_CRED_SSL_CLIENT_CERT,
+ ssl_client_cert_file_first_credentials,
+ NULL,
+ NULL
+};
/*** Public API to SSL file providers. ***/
Modified: subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c Tue Oct 15 08:52:06 2013
@@ -25,6 +25,7 @@
#include <apr_pools.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_auth.h"
#include "svn_error.h"
@@ -33,7 +34,6 @@
#include "private/svn_auth_private.h"
-#include "svn_private_config.h"
/*-----------------------------------------------------------------------*/
/* File provider */
Modified: subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c Tue Oct 15 08:52:06 2013
@@ -24,6 +24,7 @@
#include <apr_pools.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_auth.h"
#include "svn_error.h"
@@ -78,13 +79,7 @@ ssl_server_trust_file_first_credentials(
failstr = svn_hash_gets(creds_hash, AUTHN_FAILURES_KEY);
if (failstr)
- {
- char *endptr;
- unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
-
- if (*endptr == '\0')
- last_failures = (apr_uint32_t) tmp_ulong;
- }
+ SVN_ERR(svn_cstring_atoui(&last_failures, failstr->data));
/* If the cert is trusted and there are no new failures, we
* accept it by clearing all failures. */
@@ -149,9 +144,9 @@ ssl_server_trust_file_save_credentials(s
static const svn_auth_provider_t ssl_server_trust_file_provider = {
SVN_AUTH_CRED_SSL_SERVER_TRUST,
- &ssl_server_trust_file_first_credentials,
+ ssl_server_trust_file_first_credentials,
NULL,
- &ssl_server_trust_file_save_credentials,
+ ssl_server_trust_file_save_credentials,
};
Modified: subversion/branches/cache-server/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/stream.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/stream.c Tue Oct 15 08:52:06 2013
@@ -56,6 +56,7 @@ struct svn_stream_t {
svn_stream_mark_fn_t mark_fn;
svn_stream_seek_fn_t seek_fn;
svn_stream__is_buffered_fn_t is_buffered_fn;
+ apr_file_t *file; /* Maybe NULL */
};
@@ -81,6 +82,7 @@ svn_stream_create(void *baton, apr_pool_
stream->mark_fn = NULL;
stream->seek_fn = NULL;
stream->is_buffered_fn = NULL;
+ stream->file = NULL;
return stream;
}
@@ -913,6 +915,7 @@ svn_stream_from_aprfile2(apr_file_t *fil
svn_stream_set_mark(stream, mark_handler_apr);
svn_stream_set_seek(stream, seek_handler_apr);
svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
+ stream->file = file;
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
@@ -920,6 +923,12 @@ svn_stream_from_aprfile2(apr_file_t *fil
return stream;
}
+apr_file_t *
+svn_stream__aprfile(svn_stream_t *stream)
+{
+ return stream->file;
+}
+
/* Compressed stream support */
@@ -1370,6 +1379,36 @@ svn_stream_checksummed(svn_stream_t *str
/* Miscellaneous stream functions. */
+
+svn_error_t *
+svn_stringbuf_from_stream(svn_stringbuf_t **str,
+ svn_stream_t *stream,
+ apr_size_t len_hint,
+ apr_pool_t *pool)
+{
+#define MIN_READ_SIZE 64
+
+ apr_size_t to_read = 0;
+ svn_stringbuf_t *text
+ = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE, pool);
+
+ do
+ {
+ to_read = text->blocksize - 1 - text->len;
+ SVN_ERR(svn_stream_read(stream, text->data + text->len, &to_read));
+ text->len += to_read;
+
+ if (to_read && text->blocksize < text->len + MIN_READ_SIZE)
+ svn_stringbuf_ensure(text, text->blocksize * 2);
+ }
+ while (to_read);
+
+ text->data[text->len] = '\0';
+ *str = text;
+
+ return SVN_NO_ERROR;
+}
+
struct stringbuf_stream_baton
{
svn_stringbuf_t *str;
@@ -1648,7 +1687,7 @@ svn_string_from_stream(svn_string_t **re
}
-/* These are somewhat arbirary, if we ever get good empirical data as to
+/* These are somewhat arbitrary, if we ever get good empirical data as to
actually valid values, feel free to update them. */
#define BUFFER_BLOCK_SIZE 1024
#define BUFFER_MAX_SIZE 100000
@@ -1656,7 +1695,9 @@ svn_string_from_stream(svn_string_t **re
svn_stream_t *
svn_stream_buffered(apr_pool_t *result_pool)
{
- return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
+ return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE,
+ BUFFER_MAX_SIZE,
+ result_pool),
result_pool);
}
Modified: subversion/branches/cache-server/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/string.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/string.c Tue Oct 15 08:52:06 2013
@@ -53,9 +53,9 @@ membuf_create(void **data, apr_size_t *s
/* apr_palloc will allocate multiples of 8.
* Thus, we would waste some of that memory if we stuck to the
* smaller size. Note that this is safe even if apr_palloc would
- * use some other aligment or none at all. */
+ * use some other alignment or none at all. */
minimum_size = APR_ALIGN_DEFAULT(minimum_size);
- *data = (!minimum_size ? NULL : apr_palloc(pool, minimum_size));
+ *data = apr_palloc(pool, minimum_size);
*size = minimum_size;
}
@@ -121,7 +121,10 @@ svn_membuf__resize(svn_membuf_t *membuf,
const apr_size_t old_size = membuf->size;
membuf_ensure(&membuf->data, &membuf->size, size, membuf->pool);
- if (membuf->data && old_data && old_data != membuf->data)
+
+ /* If we re-allocated MEMBUF->DATA, it cannot be NULL.
+ * Statically initialized membuffers (OLD_DATA) may be NULL, though. */
+ if (old_data && old_data != membuf->data)
memcpy(membuf->data, old_data, old_size);
}
@@ -418,6 +421,17 @@ svn_stringbuf_create_from_string(const s
return svn_stringbuf_ncreate(str->data, str->len, pool);
}
+svn_stringbuf_t *
+svn_stringbuf_create_wrap(char *str, apr_pool_t *pool)
+{
+ svn_stringbuf_t *result = apr_palloc(pool, sizeof(*result));
+ result->pool = pool;
+ result->data = str;
+ result->len = strlen(str);
+ result->blocksize = result->len + 1;
+
+ return result;
+}
svn_stringbuf_t *
svn_stringbuf_createv(apr_pool_t *pool, const char *fmt, va_list ap)
@@ -595,6 +609,21 @@ svn_stringbuf_appendbytes(svn_stringbuf_
to null-terminate. */
}
+void
+svn_stringbuf_appendfill(svn_stringbuf_t *str,
+ char byte,
+ apr_size_t count)
+{
+ apr_size_t new_len = str->len + count;
+ svn_stringbuf_ensure(str, new_len);
+
+ memset(str->data + str->len, byte, count);
+
+ /* update buffer length and always NUL-terminate it */
+ str->len = new_len;
+ str->data[new_len] = '\0';
+}
+
void
svn_stringbuf_appendstr(svn_stringbuf_t *targetstr,
@@ -1027,6 +1056,36 @@ svn__strtoff(apr_off_t *offset, const ch
#endif
}
+unsigned long
+svn__strtoul(const char* buffer, const char** end)
+{
+ unsigned long result = 0;
+
+ /* this loop will execute in just 2 CPU cycles, confirmed by measurement:
+ 7 macro-ops (max 4 / cycle => 2 cycles)
+ 1 load (max 1 / cycle)
+ 1 jumps (compare + conditional jump == 1 macro op; max 1 / cycle)
+ 2 arithmetic ops (subtract, increment; max 3 / cycle)
+ 2 scale-and-add AGU ops (max 3 / cycle)
+ 1 compiler-generated move operation
+ dependency chain: temp = result * 4 + result; result = temp * 2 + c
+ (2 ops with latency 1 => 2 cycles)
+ */
+ while (1)
+ {
+ unsigned long c = *buffer - '0';
+ if (c > 9)
+ break;
+
+ result = result * 10 + c;
+ ++buffer;
+ }
+
+ *end = buffer;
+ return result;
+}
+
+
/* "Precalculated" itoa values for 2 places (including leading zeros).
* For maximum performance, make sure all table entries are word-aligned.
*/
@@ -1166,6 +1225,86 @@ svn__i64toa_sep(apr_int64_t number, char
return apr_pstrdup(pool, buffer);
}
+apr_size_t
+svn__ui64tobase36(char *dest, apr_uint64_t value)
+{
+ char *dest_start = dest;
+ if (value < 10)
+ {
+ /* pretty frequent and trivial case. Make it fast. */
+ *(dest++) = (char)(value) + '0';
+ }
+ else
+ {
+ char buffer[SVN_INT64_BUFFER_SIZE];
+ char *p = buffer;
+
+ /* write result as little-endian to buffer */
+ while (value > 0)
+ {
+ char c = (char)(value % 36);
+ value /= 36;
+
+ *p = (c <= 9) ? (c + '0') : (c - 10 + 'a');
+ ++p;
+ }
+
+ /* copy as big-endian to DEST */
+ while (p > buffer)
+ *(dest++) = *(--p);
+ }
+
+ *dest = '\0';
+ return dest - dest_start;
+}
+
+apr_uint64_t
+svn__base36toui64(const char **next, const char *source)
+{
+ apr_uint64_t result = 0;
+ apr_uint64_t factor = 1;
+ int i = 0;
+ char digits[SVN_INT64_BUFFER_SIZE];
+
+ /* convert digits to numerical values and count the number of places.
+ * Also, prevent buffer overflow. */
+ while (i < sizeof(digits))
+ {
+ char c = *source;
+ if (c < 'a')
+ {
+ /* includes detection of NUL terminator */
+ if (c < '0' || c > '9')
+ break;
+
+ c -= '0';
+ }
+ else
+ {
+ if (c < 'a' || c > 'z')
+ break;
+
+ c -= 'a' - 10;
+ }
+
+ digits[i++] = c;
+ source++;
+ }
+
+ /* fold digits into the result */
+ while (i > 0)
+ {
+ result += factor * (apr_uint64_t)digits[--i];
+ factor *= 36;
+ }
+
+ if (next)
+ *next = source;
+
+ return result;
+}
+
+
unsigned int
svn_cstring__similarity(const char *stra, const char *strb,
svn_membuf_t *buffer, apr_size_t *rlcs)
@@ -1271,3 +1410,67 @@ svn_string__similarity(const svn_string_
else
return 1000;
}
+
+apr_size_t
+svn_cstring__match_length(const char *a,
+ const char *b,
+ apr_size_t max_len)
+{
+ apr_size_t pos = 0;
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+
+ /* Chunky processing is so much faster ...
+ *
+ * We can't make this work on architectures that require aligned access
+ * because A and B will probably have different alignment. So, skipping
+ * the first few chars until alignment is reached is not an option.
+ */
+ for (; pos + sizeof(apr_size_t) <= max_len; pos += sizeof(apr_size_t))
+ if (*(const apr_size_t*)(a + pos) != *(const apr_size_t*)(b + pos))
+ break;
+
+#endif
+
+ for (; pos < max_len; ++pos)
+ if (a[pos] != b[pos])
+ break;
+
+ return pos;
+}
+
+apr_size_t
+svn_cstring__reverse_match_length(const char *a,
+ const char *b,
+ apr_size_t max_len)
+{
+ apr_size_t pos = 0;
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+
+ /* Chunky processing is so much faster ...
+ *
+ * We can't make this work on architectures that require aligned access
+ * because A and B will probably have different alignment. So, skipping
+ * the first few chars until alignment is reached is not an option.
+ */
+ for (pos = sizeof(apr_size_t); pos <= max_len; pos += sizeof(apr_size_t))
+ if (*(const apr_size_t*)(a - pos) != *(const apr_size_t*)(b - pos))
+ break;
+
+ pos -= sizeof(apr_size_t);
+
+#endif
+
+ /* If we find a mismatch at -pos, pos-1 characters matched.
+ */
+ while (++pos <= max_len)
+ if (a[0-pos] != b[0-pos])
+ return pos - 1;
+
+ /* No mismatch found -> at least MAX_LEN matching chars.
+ */
+ return max_len;
+}
+
+
Modified: subversion/branches/cache-server/subversion/libsvn_subr/subst.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/subst.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/subst.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/subst.c Tue Oct 15 08:52:06 2013
@@ -33,6 +33,7 @@
#include <apr_file_io.h>
#include <apr_strings.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_cmdline.h"
#include "svn_types.h"
@@ -47,9 +48,8 @@
#include "svn_pools.h"
#include "private/svn_io_private.h"
-#include "svn_private_config.h"
-
#include "private/svn_string_private.h"
+#include "private/svn_eol_private.h"
/**
* The textual elements of a detranslated special file. One of these
@@ -297,14 +297,23 @@ build_keywords(apr_hash_t **kw,
for (i = 0; i < keyword_tokens->nelts; ++i)
{
const char *keyword = APR_ARRAY_IDX(keyword_tokens, i, const char *);
- apr_array_header_t *custom_keyword_tokens = NULL;
+ const char *custom_fmt = NULL;
if (expand_custom_keywords)
- custom_keyword_tokens = svn_cstring_split(keyword, "=",
- TRUE /* chop */, pool);
- if (expand_custom_keywords && custom_keyword_tokens->nelts == 2)
{
- const char *custom_fmt;
+ char *sep;
+
+ /* Check if there is a custom keyword definition, started by '='. */
+ sep = strchr(keyword, '=');
+ if (sep)
+ {
+ *sep = '\0'; /* Split keyword's name from custom format. */
+ custom_fmt = sep + 1;
+ }
+ }
+
+ if (custom_fmt)
+ {
svn_string_t *custom_val;
/* Custom keywords must be allowed to match the name of an
@@ -312,9 +321,6 @@ build_keywords(apr_hash_t **kw,
* in case new fixed keywords are added to Subversion which
* happen to match a custom keyword defined somewhere.
* There is only one global namespace for keyword names. */
-
- keyword = APR_ARRAY_IDX(custom_keyword_tokens, 0, const char*);
- custom_fmt = APR_ARRAY_IDX(custom_keyword_tokens, 1, const char*);
custom_val = keyword_printf(custom_fmt, rev, url, repos_root_url,
date, author, pool);
svn_hash_sets(*kw, keyword, custom_val);
@@ -1116,28 +1122,42 @@ translate_chunk(svn_stream_t *dst,
/* skip current EOL */
len += b->eol_str_len;
- /* Check 4 bytes at once to allow for efficient pipelining
- and to reduce loop condition overhead. */
- while ((p + len + 4) <= end)
+ if (b->keywords)
{
- if (interesting[(unsigned char)p[len]]
- || interesting[(unsigned char)p[len+1]]
- || interesting[(unsigned char)p[len+2]]
- || interesting[(unsigned char)p[len+3]])
- break;
-
- len += 4;
+ /* Check 4 bytes at once to allow for efficient pipelining
+ and to reduce loop condition overhead. */
+ while ((p + len + 4) <= end)
+ {
+ if (interesting[(unsigned char)p[len]]
+ || interesting[(unsigned char)p[len+1]]
+ || interesting[(unsigned char)p[len+2]]
+ || interesting[(unsigned char)p[len+3]])
+ break;
+
+ len += 4;
+ }
+
+ /* Found an interesting char or EOF in the next 4 bytes.
+ Find its exact position. */
+ while ((p + len) < end
+ && !interesting[(unsigned char)p[len]])
+ ++len;
+ }
+ else
+ {
+ /* use our optimized sub-routine to find the next EOL */
+ const char *start = p + len;
+ const char *eol
+ = svn_eol__find_eol_start((char *)start, end - start);
+
+ /* EOL will be NULL if we did not find a line ending */
+ len += (eol ? eol : end) - start;
}
-
- /* Found an interesting char or EOF in the next 4 bytes.
- Find its exact position. */
- while ((p + len) < end && !interesting[(unsigned char)p[len]])
- ++len;
}
while (b->nl_translation_skippable ==
svn_tristate_true && /* can potentially skip EOLs */
p + len + 2 < end && /* not too close to EOF */
- eol_unchanged (b, p + len)); /* EOL format already ok */
+ eol_unchanged(b, p + len)); /* EOL format already ok */
while ((p + len) < end && !interesting[(unsigned char)p[len]])
len++;
@@ -1939,7 +1959,11 @@ svn_subst_translate_string2(svn_string_t
return SVN_NO_ERROR;
}
- if (encoding)
+ if (encoding && !strcmp(encoding, "UTF-8"))
+ {
+ val_utf8 = value->data;
+ }
+ else if (encoding)
{
SVN_ERR(svn_utf_cstring_to_utf8_ex2(&val_utf8, value->data,
encoding, scratch_pool));
Modified: subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c Tue Oct 15 08:52:06 2013
@@ -279,6 +279,26 @@ svn_temp_serializer__pop(svn_temp_serial
context->recycler = old;
}
+void
+svn_temp_serializer__add_leaf(svn_temp_serializer__context_t *context,
+ const void * const * source_struct,
+ apr_size_t struct_size)
+{
+ const void *source = *source_struct;
+
+ /* the serialized structure must be properly aligned */
+ if (source)
+ align_buffer_end(context);
+
+ /* Store the offset at which the struct data that will the appended.
+ * Write 0 for NULL pointers. */
+ store_current_end_pointer(context, source_struct);
+
+ /* finally, actually append the struct contents */
+ if (*source_struct)
+ svn_stringbuf_appendbytes(context->buffer, source, struct_size);
+}
+
/* Serialize a string referenced from the current structure within the
* serialization CONTEXT. S must be a reference to the char* pointer in
* the original structure so that the correspondence in the serialized
Modified: subversion/branches/cache-server/subversion/libsvn_subr/types.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/types.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/types.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/types.c Tue Oct 15 08:52:06 2013
@@ -24,42 +24,54 @@
#include <apr_pools.h>
#include <apr_uuid.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_types.h"
#include "svn_error.h"
#include "svn_string.h"
#include "svn_props.h"
-#include "svn_private_config.h"
+
+#include "private/svn_dep_compat.h"
+#include "private/svn_string_private.h"
svn_error_t *
svn_revnum_parse(svn_revnum_t *rev,
const char *str,
const char **endptr)
{
- char *end;
+ const char *end;
- svn_revnum_t result = strtol(str, &end, 10);
+ svn_revnum_t result = (svn_revnum_t)svn__strtoul(str, &end);
if (endptr)
- *endptr = end;
+ *endptr = str;
if (str == end)
- return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
- _("Invalid revision number found parsing '%s'"),
- str);
-
- if (result < 0)
+ return svn_error_createf
+ (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+ *str == '-' ? _("Negative revision number found parsing '%s'")
+ : _("Invalid revision number found parsing '%s'"),
+ str);
+
+ /* a revision number with more than 9 digits is suspicious.
+ Have a closer look at those. */
+ if (str + 10 <= end)
{
- /* The end pointer from strtol() is valid, but a negative revision
- number is invalid, so move the end pointer back to the
- beginning of the string. */
- if (endptr)
- *endptr = str;
-
- return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
- _("Negative revision number found parsing '%s'"),
- str);
+ /* we support 32 bit revision numbers only. check for overflows */
+ if (str + 10 < end)
+ return svn_error_createf
+ (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+ _("Revision number longer than 10 digits '%s'"), str);
+
+ /* we support 32 bit revision numbers only. check for overflows */
+ if (*str > '2' || (apr_uint32_t)result > APR_INT32_MAX)
+ return svn_error_createf
+ (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+ _("Revision number too large '%s'"), str);
}
+
+ if (endptr)
+ *endptr = end;
*rev = result;
Modified: subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c Tue Oct 15 08:52:06 2013
@@ -28,6 +28,8 @@
/*** Includes. ***/
#include <apr_pools.h>
+
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_auth.h"
#include "svn_error.h"