Jonathan Nieder wrote: > Delete all files and copy in newer versions from Subversion > upstream (http://svn.apache.org/repos/asf/subversion/trunk@982862). Here’s the “while at it” part: > While at it, port for an out-of-tree build against svn 1.6: > > - include a stripped-down version of the autoconf-generated > Makefile for Linux and a .gitignore file listing build > products; > > - use apr_hash_clear directly instead of svn_hash__clear > (since the latter’s signature has changed); > > - build and use an svn17_compat module for functions used > that were added in Subversion 1.7. > > In theory, the svn17_compat module could shrink over time > as simpler compatibility shims are devised. > > The result builds and all dump tests pass. > > Caveats: Most load tests do not pass. Chances are this will only > build against libsvn 1.6, not 1.7, since I did not do the appropriate > identifier-renaming dance. Most of this patch is Subversion code. The rest, which is my own doing, I place in the public domain. You may freely use, modify, distribute, and relicense it. .gitignore | 5 + Makefile | 35 +++ dump_editor.c | 9 +- svn17_compat.c | 842 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ svn17_compat.h | 179 ++++++++++++ svnrdump.c | 5 +- svntest/main.py | 17 +- 7 files changed, 1076 insertions(+), 16 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 svn17_compat.c create mode 100644 svn17_compat.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af251b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.lo +*.o +*.pyc +/svn-test-work/ +/svnrdump diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b022411 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +CC=gcc +PYTHON=python +LIBTOOL=libtool +LTFLAGS=--tag=CC --silent +CFLAGS=-g -O2 -pthread -Wall -Werror=implicit-function-declaration +EXEEXT= +CPPFLAGS=-DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE +LDFLAGS= +COMPILE=$(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) +LINK=$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(CFLAGS) +LT_COMPILE=$(LIBTOOL) $(LTFLAGS) --mode=compile $(COMPILE) $(CFLAGS) + +INCLUDES=-I/usr/include/subversion-1 -I/usr/include/apr-1.0 +LIBS=-lsvn_client-1 -lsvn_ra-1 -lsvn_repos-1 -lsvn_delta-1 -lsvn_subr-1 -lapr-1 +OBJECTS=dump_editor.lo load_editor.lo svnrdump.lo svn17_compat.lo + +.SUFFIXES: .c .lo + +svnrdump$(EXEEXT): $(OBJECTS) + $(LINK) $(LDFLAGS) -o svnrdump$(EXEEXT) $(OBJECTS) $(LIBS) + +.c.lo: + $(LT_COMPILE) -o $@ -c $< + +dump_editor.lo: dump_editor.c dump_editor.h svn17_compat.h +load_editor.lo: load_editor.c load_editor.h +svnrdump.lo: svnrdump.c dump_editor.h load_editor.h svn17_compat.h +svn17_compat.lo: svn17_compat.c svn17_compat.h + +check: svnrdump$(EXEEXT) svnrdump_tests.py + $(PYTHON) svnrdump_tests.py + +clean: + $(RM) svnrdump$(EXEEXT) + $(RM) *.lo *.o diff --git a/dump_editor.c b/dump_editor.c index dac9d15..72ad04f 100644 --- a/dump_editor.c +++ b/dump_editor.c @@ -29,6 +29,7 @@ #include "svn_props.h" #include "svn_dirent_uri.h" +#include "svn17_compat.h" #include "dump_editor.h" #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r)) @@ -166,8 +167,8 @@ dump_props(struct dump_edit_baton *eb, SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n")); /* Cleanup so that data is never dumped twice. */ - svn_hash__clear(eb->props, pool); - svn_hash__clear(eb->deleted_props, pool); + apr_hash_clear(eb->props); + apr_hash_clear(eb->deleted_props); if (trigger_var) *trigger_var = FALSE; } @@ -711,8 +712,8 @@ close_file(void *file_baton, /* Cleanup */ eb->dump_props = eb->dump_props_pending = FALSE; - svn_hash__clear(eb->props, pool); - svn_hash__clear(eb->deleted_props, pool); + apr_hash_clear(eb->props); + apr_hash_clear(eb->deleted_props); } /* Dump the text */ diff --git a/svn17_compat.c b/svn17_compat.c new file mode 100644 index 0000000..e6d8774 --- /dev/null +++ b/svn17_compat.c @@ -0,0 +1,842 @@ +/* + * svn17_compat.c : a library to make Subversion 1.6 look like 1.7. + * + * ==================================================================== + * This file is derived from code licensed to the Apache + * Software Foundation (ASF) under one or more contributor + * license agreements. See the NOTICE file distributed with + * this file for additional information regarding copyright + * ownership. The ASF licenses those portions to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use those portions except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Any code in this file not licensed from the ASF is + * original code in the public domain. You may freely use, + * modify, distribute, and relicense such code. + * ==================================================================== + */ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include <apr.h> +#include <apr_strings.h> +#include <apr_hash.h> +#include <apr_lib.h> +#include <apr_errno.h> +#include <apr_pools.h> + +#include <svn_error.h> +#include <svn_config.h> +#include <svn_io.h> +#include <svn_dirent_uri.h> +#include <svn_path.h> +#include "svn17_compat.h" + +/* TRUE if s is the canonical empty path, FALSE otherwise + From libsvn_subr/dirent_uri.c. */ +#define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0') + +/* Path type definition. Used only by internal functions. + From libsvn_subr/dirent_uri.c. */ +typedef enum { + type_uri, + type_dirent, + type_relpath +} path_type_t; + +/* Here is the BNF for path components in a URI. "pchar" is a + character in a path component. + + pchar = unreserved | escaped | + ":" | "@" | "&" | "=" | "+" | "$" | "," + unreserved = alphanum | mark + mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + + Note that "escaped" doesn't really apply to what users can put in + their paths, so that really means the set of characters is: + + alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | "," + + From libsvn_subr/path.c. */ +static const char svn_uri__char_validity[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, + + /* 64 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, + + /* 128 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* 192 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* From libsvn_subr/dirent_uri.c. */ +static svn_boolean_t +svn_uri_is_canonical(const char *uri, apr_pool_t *pool) +{ + const char *ptr = uri, *seg = uri; + const char *schema_data = NULL; + + /* URI is canonical if it has: + * - no '.' segments + * - no closing '/', unless for the root path '/' itself + * - no '//' + * - lowercase URL scheme + * - lowercase URL hostname + */ + + if (*uri == '\0') + return TRUE; + + /* Maybe parse hostname and scheme. */ + if (*ptr != '/') + { + while (*ptr && (*ptr != '/') && (*ptr != ':')) + ptr++; + + if (*ptr == ':' && *(ptr+1) == '/' && *(ptr+2) == '/') + { + /* Found a scheme, check that it's all lowercase. */ + ptr = uri; + while (*ptr != ':') + { + if (*ptr >= 'A' && *ptr <= 'Z') + return FALSE; + ptr++; + } + /* Skip :// */ + ptr += 3; + + /* This might be the hostname */ + seg = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '@')) + ptr++; + + if (! *ptr) + return TRUE; + + if (*ptr == '@') + seg = ptr + 1; + + /* Found a hostname, check that it's all lowercase. */ + ptr = seg; + while (*ptr && *ptr != '/') + { + if (*ptr >= 'A' && *ptr <= 'Z') + return FALSE; + ptr++; + } + + schema_data = ptr; + } + else + { + /* Didn't find a scheme; finish the segment. */ + while (*ptr && *ptr != '/') + ptr++; + } + } + +#ifdef SVN_USE_DOS_PATHS + if (schema_data && *ptr == '/') + { + /* If this is a file url, ptr now points to the third '/' in + file:///C:/path. Check that if we have such a URL the drive + letter is in uppercase. */ + if (strncmp(uri, "file:", 5) == 0 && + ! (*(ptr+1) >= 'A' && *(ptr+1) <= 'Z') && + *(ptr+2) == ':') + return FALSE; + } +#endif /* SVN_USE_DOS_PATHS */ + + /* Now validate the rest of the URI. */ + while(1) + { + apr_size_t seglen = ptr - seg; + + if (seglen == 1 && *seg == '.') + return FALSE; /* /./ */ + + if (*ptr == '/' && *(ptr+1) == '/') + return FALSE; /* // */ + + if (! *ptr && *(ptr - 1) == '/' && ptr - 1 != uri) + return FALSE; /* foo/ */ + + if (! *ptr) + break; + + if (*ptr == '/') + ptr++; + seg = ptr; + + + while (*ptr && (*ptr != '/')) + ptr++; + } + + if (schema_data) + { + ptr = schema_data; + + while (*ptr) + { + if (*ptr == '%') + { + char digitz[3]; + int val; + + /* Can't use apr_isxdigit() because lower case letters are + not in our canonical format */ + if (((*(ptr+1) < '0' || (*ptr+1) > '9')) + && (*(ptr+1) < 'A' || (*ptr+1) > 'F')) + return FALSE; + else if (((*(ptr+2) < '0' || (*ptr+2) > '9')) + && (*(ptr+2) < 'A' || (*ptr+2) > 'F')) + return FALSE; + + digitz[0] = *(++ptr); + digitz[1] = *(++ptr); + digitz[2] = '\0'; + val = (int)strtol(digitz, NULL, 16); + + if (svn_uri__char_validity[val]) + return FALSE; /* Should not have been escaped */ + } + else if (*ptr != '/' && !svn_uri__char_validity[(unsigned char)*ptr]) + return FALSE; /* Character should have been escaped */ + ptr++; + } + } + + return TRUE; +} + +/* From libsvn_subr/dirent_uri.c. */ +static svn_boolean_t +svn_uri_is_absolute(const char *uri) +{ + /* uri is absolute if it starts with '/' */ + if (uri && uri[0] == '/') + return TRUE; + + /* URLs are absolute. */ + return svn_path_is_url(uri); +} + +/* Calculates the length occupied by the schema defined root of URI + From libsvn_subr/dirent_uri.c. */ +static apr_size_t +uri_schema_root_length(const char *uri, apr_size_t len) +{ + apr_size_t i; + + for (i = 0; i < len; i++) + { + if (uri[i] == '/') + { + if (i > 0 && uri[i-1] == ':' && i < len-1 && uri[i+1] == '/') + { + /* We have an absolute uri */ + if (i == 5 && strncmp("file", uri, 4) == 0) + return 7; /* file:// */ + else + { + for (i += 2; i < len; i++) + if (uri[i] == '/') + return i; + + return len; /* Only a hostname is found */ + } + } + else + return 0; + } + } + + return 0; +} + +/* From libsvn_subr/dirent_uri.c. */ +char * +svn_uri_join(const char *base, const char *component, apr_pool_t *pool) +{ + apr_size_t blen = strlen(base); + apr_size_t clen = strlen(component); + char *path; + + assert(svn_uri_is_canonical(base, pool)); + assert(svn_uri_is_canonical(component, pool)); + + /* If either is empty return the other */ + if (SVN_PATH_IS_EMPTY(base)) + return apr_pmemdup(pool, component, clen + 1); + if (SVN_PATH_IS_EMPTY(component)) + return apr_pmemdup(pool, base, blen + 1); + + /* If the component is absolute, then return it. */ + if (svn_uri_is_absolute(component)) + { + if (*component != '/') + return apr_pmemdup(pool, component, clen + 1); + else + { + /* The uri is not absolute enough; use only the root from base */ + apr_size_t n = uri_schema_root_length(base, blen); + + path = apr_palloc(pool, n + clen + 1); + + if (n > 0) + memcpy(path, base, n); + + memcpy(path + n, component, clen + 1); /* Include '\0' */ + + return path; + } + } + + if (blen == 1 && base[0] == '/') + blen = 0; /* Ignore base, just return separator + component */ + + /* Construct the new, combined path. */ + path = apr_palloc(pool, blen + 1 + clen + 1); + memcpy(path, base, blen); + path[blen] = '/'; + memcpy(path + blen + 1, component, clen + 1); + + return path; +} + +/* From libsvn_subr/dirent_uri.c. */ +static svn_boolean_t +svn_relpath_is_canonical(const char *relpath, + apr_pool_t *pool) +{ + const char *ptr = relpath, *seg = relpath; + + /* RELPATH is canonical if it has: + * - no '.' segments + * - no start and closing '/' + * - no '//' + */ + + if (*relpath == '\0') + return TRUE; + + if (*ptr == '/') + return FALSE; + + /* Now validate the rest of the path. */ + while(1) + { + apr_size_t seglen = ptr - seg; + + if (seglen == 1 && *seg == '.') + return FALSE; /* /./ */ + + if (*ptr == '/' && *(ptr+1) == '/') + return FALSE; /* // */ + + if (! *ptr && *(ptr - 1) == '/') + return FALSE; /* foo/ */ + + if (! *ptr) + break; + + if (*ptr == '/') + ptr++; + seg = ptr; + + while (*ptr && (*ptr != '/')) + ptr++; + } + + return TRUE; +} + +/* From libsvn_subr/dirent_uri.c. */ +const char * +svn_relpath_basename(const char *relpath, + apr_pool_t *pool) +{ + apr_size_t len = strlen(relpath); + apr_size_t start; + + assert(!pool || svn_relpath_is_canonical(relpath, pool)); + + start = len; + while (start > 0 && relpath[start - 1] != '/') + --start; + + if (pool) + return apr_pstrmemdup(pool, relpath + start, len - start); + else + return relpath + start; +} + +/* From libsvn_subr/dirent_uri.c. */ +const char * +svn_dirent_basename(const char *dirent, apr_pool_t *pool) +{ + apr_size_t len = strlen(dirent); + apr_size_t start; + + assert(!pool || svn_dirent_is_canonical(dirent, pool)); + + if (svn_dirent_is_root(dirent, len)) + return ""; + else + { + start = len; + while (start > 0 && dirent[start - 1] != '/' +#ifdef SVN_USE_DOS_PATHS + && dirent[start - 1] != ':' +#endif + ) + --start; + } + + if (pool) + return apr_pstrmemdup(pool, dirent + start, len - start); + else + return dirent + start; +} + +/* Locale insensitive tolower() for converting parts of dirents and urls + while canonicalizing. From libsvn_subr/dirent_uri.c. */ +static char +canonicalize_to_lower(char c) +{ + if (c < 'A' || c > 'Z') + return c; + else + return c - 'A' + 'a'; +} + +/* Locale insensitive toupper() for converting parts of dirents and urls + while canonicalizing. From libsvn_subr/dirent_uri.c. */ +static char +canonicalize_to_upper(char c) +{ + if (c < 'a' || c > 'z') + return c; + else + return c - 'a' + 'A'; +} + + +/* Return the canonicalized version of PATH, of type TYPE, allocated in + * POOL. From libsvn_subr/dirent_uri.c. + */ +static const char * +canonicalize(path_type_t type, const char *path, apr_pool_t *pool) +{ + char *canon, *dst; + const char *src; + apr_size_t seglen; + apr_size_t schemelen = 0; + apr_size_t canon_segments = 0; + svn_boolean_t url = FALSE; + char *schema_data = NULL; + + /* "" is already canonical, so just return it; note that later code + depends on path not being zero-length. */ + if (SVN_PATH_IS_EMPTY(path)) + return ""; + + dst = canon = apr_pcalloc(pool, strlen(path) + 1); + + /* If this is supposed to be an URI and it starts with "scheme://", then + copy the scheme, host name, etc. to DST and set URL = TRUE. */ + src = path; + if (type == type_uri && *src != '/') + { + while (*src && (*src != '/') && (*src != ':')) + src++; + + if (*src == ':' && *(src+1) == '/' && *(src+2) == '/') + { + const char *seg; + + url = TRUE; + + /* Found a scheme, convert to lowercase and copy to dst. */ + src = path; + while (*src != ':') + { + *(dst++) = canonicalize_to_lower((*src++)); + schemelen++; + } + *(dst++) = ':'; + *(dst++) = '/'; + *(dst++) = '/'; + src += 3; + schemelen += 3; + + /* This might be the hostname */ + seg = src; + while (*src && (*src != '/') && (*src != '@')) + src++; + + if (*src == '@') + { + /* Copy the username & password. */ + seglen = src - seg + 1; + memcpy(dst, seg, seglen); + dst += seglen; + src++; + } + else + src = seg; + + /* Found a hostname, convert to lowercase and copy to dst. */ + while (*src && (*src != '/')) + *(dst++) = canonicalize_to_lower((*src++)); + + /* Copy trailing slash, or null-terminator. */ + *(dst) = *(src); + + /* Move src and dst forward only if we are not + * at null-terminator yet. */ + if (*src) + { + src++; + dst++; + schema_data = dst; + } + + canon_segments = 1; + } + } + + /* Copy to DST any separator or drive letter that must come before the + first regular path segment. */ + if (! url && type != type_relpath) + { + src = path; + /* If this is an absolute path, then just copy over the initial + separator character. */ + if (*src == '/') + { + *(dst++) = *(src++); + +#ifdef SVN_USE_DOS_PATHS + /* On Windows permit two leading separator characters which means an + * UNC path. */ + if ((type == type_dirent) && *src == '/') + *(dst++) = *(src++); +#endif /* SVN_USE_DOS_PATHS */ + } +#ifdef SVN_USE_DOS_PATHS + /* On Windows the first segment can be a drive letter, which we normalize + to upper case. */ + else if (type == type_dirent && + ((*src >= 'a' && *src <= 'z') || + (*src >= 'A' && *src <= 'Z')) && + (src[1] == ':')) + { + *(dst++) = canonicalize_to_upper(*(src++)); + /* Leave the ':' to be processed as (or as part of) a path segment + by the following code block, so we need not care whether it has + a slash after it. */ + } +#endif /* SVN_USE_DOS_PATHS */ + } + + while (*src) + { + /* Parse each segment, find the closing '/' */ + const char *next = src; + while (*next && (*next != '/')) + ++next; + + seglen = next - src; + + if (seglen == 0 || (seglen == 1 && src[0] == '.')) + { + /* Noop segment, so do nothing. */ + } +#ifdef SVN_USE_DOS_PATHS + /* If this is the first path segment of a file:// URI and it contains a + windows drive letter, convert the drive letter to upper case. */ + else if (url && canon_segments == 1 && seglen == 2 && + (strncmp(canon, "file:", 5) == 0) && + src[0] >= 'a' && src[0] <= 'z' && src[1] == ':') + { + *(dst++) = canonicalize_to_upper(src[0]); + *(dst++) = ':'; + if (*next) + *(dst++) = *next; + canon_segments++; + } +#endif /* SVN_USE_DOS_PATHS */ + else + { + /* An actual segment, append it to the destination path */ + if (*next) + seglen++; + memcpy(dst, src, seglen); + dst += seglen; + canon_segments++; + } + + /* Skip over trailing slash to the next segment. */ + src = next; + if (*src) + src++; + } + + /* Remove the trailing slash if there was at least one + * canonical segment and the last segment ends with a slash. + * + * But keep in mind that, for URLs, the scheme counts as a + * canonical segment -- so if path is ONLY a scheme (such + * as "https://") we should NOT remove the trailing slash. */ + if ((canon_segments > 0 && *(dst - 1) == '/') + && ! (url && path[schemelen] == '\0')) + { + dst --; + } + + *dst = '\0'; + +#ifdef SVN_USE_DOS_PATHS + /* Skip leading double slashes when there are less than 2 + * canon segments. UNC paths *MUST* have two segments. */ + if ((type == type_dirent) && canon[0] == '/' && canon[1] == '/') + { + if (canon_segments < 2) + return canon + 1; + else + { + /* Now we're sure this is a valid UNC path, convert the server name + (the first path segment) to lowercase as Windows treats it as case + insensitive. + Note: normally the share name is treated as case insensitive too, + but it seems to be possible to configure Samba to treat those as + case sensitive, so better leave that alone. */ + dst = canon + 2; + while (*dst && *dst != '/') + *(dst++) = canonicalize_to_lower(*dst); + } + } +#endif /* SVN_USE_DOS_PATHS */ + + /* Check the normalization of characters in a uri */ + if (schema_data) + { + int need_extra = 0; + src = schema_data; + + while (*src) + { + switch (*src) + { + case '/': + break; + case '%': + if (!apr_isxdigit(*(src+1)) || !apr_isxdigit(*(src+2))) + need_extra += 2; + else + src += 2; + break; + default: + if (!svn_uri__char_validity[(unsigned char)*src]) + need_extra += 2; + break; + } + src++; + } + + if (need_extra > 0) + { + apr_size_t pre_schema_size = (apr_size_t)(schema_data - canon); + + dst = apr_palloc(pool, (apr_size_t)(src - canon) + need_extra + 1); + memcpy(dst, canon, pre_schema_size); + canon = dst; + + dst += pre_schema_size; + } + else + dst = schema_data; + + src = schema_data; + + while (*src) + { + switch (*src) + { + case '/': + *(dst++) = '/'; + break; + case '%': + if (!apr_isxdigit(*(src+1)) || !apr_isxdigit(*(src+2))) + { + *(dst++) = '%'; + *(dst++) = '2'; + *(dst++) = '5'; + } + else + { + char digitz[3]; + int val; + + digitz[0] = *(++src); + digitz[1] = *(++src); + digitz[2] = 0; + + val = (int)strtol(digitz, NULL, 16); + + if (svn_uri__char_validity[(unsigned char)val]) + *(dst++) = (char)val; + else + { + *(dst++) = '%'; + *(dst++) = canonicalize_to_upper(digitz[0]); + *(dst++) = canonicalize_to_upper(digitz[1]); + } + } + break; + default: + if (!svn_uri__char_validity[(unsigned char)*src]) + { + apr_snprintf(dst, 4, "%%%02X", (unsigned char)*src); + dst += 3; + } + else + *(dst++) = *src; + break; + } + src++; + } + *dst = '\0'; + } + + return canon; +} + +/* From libsvn_subr/dirent_uri.c. */ +const char * +svn_uri_canonicalize(const char *uri, apr_pool_t *pool) +{ + return canonicalize(type_uri, uri, pool); +} + +/* New code (public domain). */ +svn_error_t * +svn_io_remove_file2(const char *path, + svn_boolean_t ignore_enoent, + apr_pool_t *scratch_pool) +{ + svn_error_t *err = svn_io_remove_file(path, scratch_pool); + if (ignore_enoent && err && APR_STATUS_IS_ENOENT(err->apr_err)) + { + svn_error_clear(err); + return SVN_NO_ERROR; + } + return err; +} + +/* From libsvn_subr/cmdline.c. */ +svn_error_t * +svn_cmdline__apply_config_options(apr_hash_t *config, + const apr_array_header_t *config_options, + const char *prefix, + const char *argument_name) +{ + int i; + + for (i = 0; i < config_options->nelts; i++) + { + svn_config_t *cfg; + svn_cmdline__config_argument_t *arg = + APR_ARRAY_IDX(config_options, i, + svn_cmdline__config_argument_t *); + + cfg = apr_hash_get(config, arg->file, APR_HASH_KEY_STRING); + + if (cfg) + { + svn_config_set(cfg, arg->section, arg->option, arg->value); + } + else + { + svn_error_t *err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Unrecognized file in argument of %s"), argument_name); + + svn_handle_warning2(stderr, err, prefix); + svn_error_clear(err); + } + } + + return SVN_NO_ERROR; +} + +/* From libsvn_subr/cmdline.c. */ +svn_error_t * +svn_cmdline__parse_config_option(apr_array_header_t *config_options, + const char *opt_arg, + apr_pool_t *pool) +{ + svn_cmdline__config_argument_t *config_option; + const char *first_colon, *second_colon, *equals_sign; + apr_size_t len = strlen(opt_arg); + if ((first_colon = strchr(opt_arg, ':')) && (first_colon != opt_arg)) + { + if ((second_colon = strchr(first_colon + 1, ':')) && + (second_colon != first_colon + 1)) + { + if ((equals_sign = strchr(second_colon + 1, '=')) && + (equals_sign != second_colon + 1)) + { + config_option = apr_pcalloc(pool, sizeof(*config_option)); + config_option->file = apr_pstrndup(pool, opt_arg, + first_colon - opt_arg); + config_option->section = apr_pstrndup(pool, first_colon + 1, + second_colon - first_colon - 1); + config_option->option = apr_pstrndup(pool, second_colon + 1, + equals_sign - second_colon - +1); + + if (! (strchr(config_option->option, ':'))) + { + config_option->value = apr_pstrndup(pool, equals_sign + 1, + opt_arg + len - equals_sign - 1); + APR_ARRAY_PUSH(config_options, svn_cmdline__config_argument_t +*) + = config_option; + return SVN_NO_ERROR; + } + } + } + } + return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Invalid syntax of argument of --config-option")); +} diff --git a/svn17_compat.h b/svn17_compat.h new file mode 100644 index 0000000..2c48cd6 --- /dev/null +++ b/svn17_compat.h @@ -0,0 +1,179 @@ +/** + * @copyright + * ==================================================================== + * This file is derived from code licensed to the Apache + * Software Foundation (ASF) under one or more contributor + * license agreements. See the NOTICE file distributed with + * this file for additional information regarding copyright + * ownership. The ASF licenses those portions to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use those portions except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * Any code in this file not licensed from the ASF is + * original code in the public domain. You may freely use, + * modify, distribute, and relicense such code. + * ==================================================================== + * @endcopyright + * + * @file compat.h + * @brief SVN 1.7 compatibility routines. + */ + +#ifndef SVN17_COMPAT_H +#define SVN17_COMPAT_H + +#include <apr.h> +#include <apr_pools.h> + +#include <svn_types.h> + +/** Join a valid base uri (@a base) with a relative path or uri + * (@a component), allocating the result in @a pool. @a component need + * not be a single component: it can be a relative path or a '/' + * prefixed relative path to join component to the root path of @a base. + * + * If @a component is the empty path, then @a base will be copied and + * returned. + * + * If the @a component is an absolute uri, then it is copied and returned. + * + * If @a component starts with a '/' and @a base contains a scheme, the + * scheme defined joining rules are applied. + * + * From svn_dirent_uri.h. + */ +char * +svn_uri_join(const char *base, + const char *component, + apr_pool_t *pool); + +/** Get the basename of the specified canonicalized @a relpath. The + * basename is defined as the last component of the relpath. If the @a + * relpath has only one component then that is returned. The returned + * value will have no slashes in it. + * + * Example: svn_relpath_basename("/trunk/foo/bar") -> "bar" + * + * The returned basename will be allocated in @a pool. If @a + * pool is NULL a pointer to the basename in @a relpath is returned. + * + * @note If an empty string is passed, then an empty string will be returned. + * + * From svn_dirent_uri.h. + */ +const char * +svn_relpath_basename(const char *uri, + apr_pool_t *pool); + +/** Gets the name of the specified canonicalized @a dirent as it is known + * within its parent directory. If the @a dirent is root, return "". The + * returned value will not have slashes in it. + * + * Example: svn_dirent_basename("/foo/bar") -> "bar" + * + * The returned basename will be allocated in @a pool. If @a pool is NULL + * a pointer to the basename in @a dirent is returned. + * + * @note If an empty string is passed, then an empty string will be returned. + * + * From svn_dirent_uri.h. + */ +const char * +svn_dirent_basename(const char *dirent, + apr_pool_t *pool); + +/** Return a new uri like @a uri, but transformed such that some types + * of uri specification redundancies are removed. + * + * This involves collapsing redundant "/./" elements, removing + * multiple adjacent separator characters, removing trailing + * separator characters, and possibly other semantically inoperative + * transformations. + * + * If @a uri starts with a schema, this function also normalizes the + * escaping of the path component by unescaping characters that don't + * need escaping and escaping characters that do need escaping but + * weren't. + * + * This functions supports URLs. + * + * The returned uri may be statically allocated or allocated from @a pool. + * + * From svn_dirent_uri.h. + */ +const char * +svn_uri_canonicalize(const char *uri, + apr_pool_t *pool); + +/** Remove file @a path, a utf8-encoded path. This wraps apr_file_remove(), + * converting any error to a Subversion error. If @a ignore_enoent is TRUE, and + * the file is not present (APR_STATUS_IS_ENOENT returns TRUE), then no + * error will be returned. + * + * From svn_io.h. + */ +svn_error_t * +svn_io_remove_file2(const char *path, + svn_boolean_t ignore_enoent, + apr_pool_t *scratch_pool); + +/* From svn_private_config.h. + */ +#define PACKAGE_NAME "subversion" +#define N_(x) x +#include <locale.h> +#include <libintl.h> +#define _(x) dgettext(PACKAGE_NAME, x) + +/** Sets the config options in @a config_options, an apr array containing + * svn_cmdline__config_argument_t* elements to the configuration in @a cfg, + * a hash mapping of <tt>const char *</tt> configuration file names to + * @c svn_config_t *'s. Write warnings to stderr. + * + * Use @a prefix as prefix and @a argument_name in warning messages. + * + * From private/svn_cmdline_private.h. + */ +svn_error_t * +svn_cmdline__apply_config_options(apr_hash_t *config, + const apr_array_header_t *config_options, + const char *prefix, + const char *argument_name); + +/** Container for config options parsed with svn_cmdline__parse_config_option + * + * From private/svn_cmdline_private.h. + */ +typedef struct svn_cmdline__config_argument_t +{ + const char *file; + const char *section; + const char *option; + const char *value; +} svn_cmdline__config_argument_t; + +/** Parser for 'FILE:SECTION:OPTION=[VALUE]'-style option arguments. + * + * Parses @a opt_arg and places its value in @a config_options, an apr array + * containing svn_cmdline__config_argument_t* elements, allocating the option + * data in @a pool + * + * From private/svn_cmdline_private.h. + */ +svn_error_t * +svn_cmdline__parse_config_option(apr_array_header_t *config_options, + const char *opt_arg, + apr_pool_t *pool); + + +#endif /* SVN17_COMPAT_H */ diff --git a/svnrdump.c b/svnrdump.c index daf826e..a320b24 100644 --- a/svnrdump.c +++ b/svnrdump.c @@ -30,15 +30,14 @@ #include "svn_repos.h" #include "svn_path.h" #include "svn_utf.h" -#include "svn_private_config.h" #include "svn_string.h" #include "svn_props.h" +#include "svn_dirent_uri.h" +#include "svn17_compat.h" #include "dump_editor.h" #include "load_editor.h" -#include "private/svn_cmdline_private.h" - static svn_opt_subcommand_t dump_cmd, load_cmd; enum svn_svnrdump__longopt_t diff --git a/svntest/main.py b/svntest/main.py index 2c59101..3e938d6 100644 --- a/svntest/main.py +++ b/svntest/main.py @@ -149,15 +149,14 @@ def url2pathname(path): # The locations of the svn, svnadmin and svnlook binaries, relative to # the only scripts that import this file right now (they live in ../). # Use --bin to override these defaults. -svn_binary = os.path.abspath('../../svn/svn' + _exe) -svnadmin_binary = os.path.abspath('../../svnadmin/svnadmin' + _exe) -svnlook_binary = os.path.abspath('../../svnlook/svnlook' + _exe) -svnrdump_binary = os.path.abspath('../../svnrdump/svnrdump' + _exe) -svnsync_binary = os.path.abspath('../../svnsync/svnsync' + _exe) -svnversion_binary = os.path.abspath('../../svnversion/svnversion' + _exe) -svndumpfilter_binary = os.path.abspath('../../svndumpfilter/svndumpfilter' + \ - _exe) -entriesdump_binary = os.path.abspath('entries-dump' + _exe) +svn_binary = 'svn' +svnadmin_binary = 'svnadmin' +svnlook_binary = 'svnlook' +svnrdump_binary = os.path.abspath('./svnrdump' + _exe) +svnsync_binary = 'svnsync' +svnversion_binary = 'svnversion' +svndumpfilter_binary = 'svndumpfilter' +entriesdump_binary = 'entries-dump' # Location to the pristine repository, will be calculated from test_area_url # when we know what the user specified for --url. -- 1.7.2.1.544.ga752d.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html