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 2010/12/02 21:55:18 UTC
svn commit: r1041580 [9/35] - in
/subversion/branches/gpg-agent-password-store: ./ build/ build/ac-macros/
build/generator/ build/generator/templates/ build/win32/
contrib/hook-scripts/ contrib/server-side/ notes/http-and-webdav/
notes/wc-ng/ subversio...
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/dirent_uri.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/dirent_uri.c Thu Dec 2 20:55:08 2010
@@ -63,7 +63,13 @@ typedef enum {
type_relpath
} path_type_t;
-
+
+/**** Forward declarations *****/
+
+static svn_boolean_t
+relpath_is_canonical(const char *relpath);
+
+
/**** Internal implementation functions *****/
/* Return an internal-style new path based on PATH, allocated in POOL.
@@ -1189,8 +1195,8 @@ svn_relpath_join(const char *base,
apr_size_t clen = strlen(component);
char *path;
- assert(svn_relpath_is_canonical(base, pool));
- assert(svn_relpath_is_canonical(component, pool));
+ assert(relpath_is_canonical(base));
+ assert(relpath_is_canonical(component));
/* If either is empty return the other */
if (blen == 0)
@@ -1316,7 +1322,7 @@ svn_relpath_dirname(const char *relpath,
{
apr_size_t len = strlen(relpath);
- assert(svn_relpath_is_canonical(relpath, pool));
+ assert(relpath_is_canonical(relpath));
return apr_pstrmemdup(pool, relpath,
relpath_previous_segment(relpath, len));
@@ -1329,7 +1335,7 @@ svn_relpath_basename(const char *relpath
apr_size_t len = strlen(relpath);
apr_size_t start;
- assert(!pool || svn_relpath_is_canonical(relpath, pool));
+ assert(relpath_is_canonical(relpath));
start = len;
while (start > 0 && relpath[start - 1] != '/')
@@ -1422,6 +1428,9 @@ svn_relpath_get_longest_ancestor(const c
const char *relpath2,
apr_pool_t *pool)
{
+ assert(relpath_is_canonical(relpath1));
+ assert(relpath_is_canonical(relpath2));
+
return apr_pstrndup(pool, relpath1,
get_longest_ancestor_length(type_relpath, relpath1,
relpath2, pool));
@@ -1497,6 +1506,9 @@ svn_relpath_is_child(const char *parent_
const char *child_relpath,
apr_pool_t *pool)
{
+ /* assert(relpath_is_canonical(parent_relpath)); */
+ /* assert(relpath_is_canonical(child_relpath)); */
+
return is_child(type_relpath, parent_relpath, child_relpath, pool);
}
@@ -1517,6 +1529,9 @@ svn_dirent_is_ancestor(const char *paren
svn_boolean_t
svn_relpath_is_ancestor(const char *parent_relpath, const char *child_relpath)
{
+ assert(relpath_is_canonical(parent_relpath));
+ assert(relpath_is_canonical(child_relpath));
+
return is_ancestor(type_relpath, parent_relpath, child_relpath);
}
@@ -1563,15 +1578,15 @@ svn_relpath_skip_ancestor(const char *pa
{
apr_size_t len = strlen(parent_relpath);
+ assert(relpath_is_canonical(parent_relpath));
+ assert(relpath_is_canonical(child_relpath));
+
if (0 != memcmp(parent_relpath, child_relpath, len))
return child_relpath; /* parent_relpath is no ancestor of child_relpath */
if (child_relpath[len] == 0)
return ""; /* parent_relpath == child_relpath */
- if (len == 1 && child_relpath[0] == '/')
- return child_relpath + 1;
-
if (child_relpath[len] == '/')
return child_relpath + len + 1;
@@ -1737,12 +1752,11 @@ svn_dirent_is_canonical(const char *dire
}
#endif /* SVN_USE_DOS_PATHS */
- return svn_relpath_is_canonical(ptr, pool);
+ return relpath_is_canonical(ptr);
}
-svn_boolean_t
-svn_relpath_is_canonical(const char *relpath,
- apr_pool_t *pool)
+static svn_boolean_t
+relpath_is_canonical(const char *relpath)
{
const char *ptr = relpath, *seg = relpath;
@@ -1787,6 +1801,13 @@ svn_relpath_is_canonical(const char *rel
}
svn_boolean_t
+svn_relpath_is_canonical(const char *relpath,
+ apr_pool_t *pool)
+{
+ return relpath_is_canonical(relpath);
+}
+
+svn_boolean_t
svn_uri_is_canonical(const char *uri, apr_pool_t *pool)
{
const char *ptr = uri, *seg = uri;
@@ -2444,3 +2465,167 @@ svn_uri_get_file_url_from_dirent(const c
return SVN_NO_ERROR;
}
+
+
+/* ------------------------ The fspath API ------------------------ */
+
+svn_boolean_t
+svn_fspath__is_canonical(const char *fspath)
+{
+ return fspath[0] == '/' && relpath_is_canonical(fspath + 1);
+}
+
+
+const char *
+svn_fspath__is_child(const char *parent_fspath,
+ const char *child_fspath,
+ apr_pool_t *pool)
+{
+ const char *result;
+ assert(svn_fspath__is_canonical(parent_fspath));
+ assert(svn_fspath__is_canonical(child_fspath));
+
+#ifdef FSPATH_USE_URI
+ result = svn_uri_is_child(parent_fspath, child_fspath, pool);
+#else
+ result = svn_relpath_is_child(parent_fspath + 1, child_fspath + 1, pool);
+#endif
+
+ assert(result == NULL || svn_relpath_is_canonical(result, pool));
+ return result;
+}
+
+const char *
+svn_fspath__skip_ancestor(const char *parent_fspath,
+ const char *child_fspath)
+{
+ const char *result;
+ assert(svn_fspath__is_canonical(parent_fspath));
+ assert(svn_fspath__is_canonical(child_fspath));
+
+#ifdef FSPATH_USE_URI
+ result = svn_uri_skip_ancestor(parent_fspath, child_fspath);
+#else
+ if (svn_relpath_is_ancestor(parent_fspath + 1, child_fspath + 1))
+ result = svn_relpath_skip_ancestor(parent_fspath + 1, child_fspath + 1);
+ else
+ result = child_fspath;
+#endif
+
+ assert(svn_relpath_is_canonical(result, NULL)
+ || strcmp(result, child_fspath) == 0);
+ return result;
+}
+
+svn_boolean_t
+svn_fspath__is_ancestor(const char *parent_fspath,
+ const char *child_fspath)
+{
+ assert(svn_fspath__is_canonical(parent_fspath));
+ assert(svn_fspath__is_canonical(child_fspath));
+
+#ifdef FSPATH_USE_URI
+ return svn_uri_is_ancestor(parent_fspath, child_fspath);
+#else
+ return svn_relpath_is_ancestor(parent_fspath + 1, child_fspath + 1);
+#endif
+}
+
+
+const char *
+svn_fspath__dirname(const char *fspath,
+ apr_pool_t *pool)
+{
+ const char *result;
+ assert(svn_fspath__is_canonical(fspath));
+
+#ifdef FSPATH_USE_URI
+ result = svn_uri_dirname(fspath, pool);
+#else
+ result = apr_pstrcat(pool, "/", svn_relpath_dirname(fspath + 1, pool),
+ (char *)NULL);
+#endif
+
+ assert(svn_fspath__is_canonical(result));
+ return result;
+}
+
+
+const char *
+svn_fspath__basename(const char *fspath,
+ apr_pool_t *pool)
+{
+ const char *result;
+ assert(svn_fspath__is_canonical(fspath));
+
+#ifdef FSPATH_USE_URI
+ result = svn_uri_basename(fspath, pool);
+#else
+ result = svn_relpath_basename(fspath + 1, pool);
+#endif
+
+ assert(strchr(result, '/') == NULL);
+ return result;
+}
+
+void
+svn_fspath__split(const char **dirpath,
+ const char **base_name,
+ const char *fspath,
+ apr_pool_t *result_pool)
+{
+ assert(dirpath != base_name);
+
+ if (dirpath)
+ *dirpath = svn_fspath__dirname(fspath, result_pool);
+
+ if (base_name)
+ *base_name = svn_fspath__basename(fspath, result_pool);
+}
+
+char *
+svn_fspath__join(const char *fspath,
+ const char *relpath,
+ apr_pool_t *result_pool)
+{
+ char *result;
+ assert(svn_fspath__is_canonical(fspath));
+ assert(svn_relpath_is_canonical(relpath, result_pool));
+
+#ifdef FSPATH_USE_URI
+ result = svn_uri_join(fspath, relpath, result_pool);
+#else
+ if (relpath[0] == '\0')
+ result = apr_pstrdup(result_pool, fspath);
+ else if (fspath[1] == '\0')
+ result = apr_pstrcat(result_pool, "/", relpath, (char *)NULL);
+ else
+ result = apr_pstrcat(result_pool, fspath, "/", relpath, (char *)NULL);
+#endif
+
+ assert(svn_fspath__is_canonical(result));
+ return result;
+}
+
+char *
+svn_fspath__get_longest_ancestor(const char *fspath1,
+ const char *fspath2,
+ apr_pool_t *result_pool)
+{
+ char *result;
+ assert(svn_fspath__is_canonical(fspath1));
+ assert(svn_fspath__is_canonical(fspath2));
+
+#ifdef FSPATH_USE_URI
+ result = svn_uri_get_longest_ancestor(fspath1, fspath2, result_pool);
+#else
+ result = apr_pstrcat(result_pool, "/",
+ svn_relpath_get_longest_ancestor(fspath1 + 1,
+ fspath2 + 1,
+ result_pool),
+ NULL);
+#endif
+
+ assert(svn_fspath__is_canonical(result));
+ return result;
+}
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/eol.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/eol.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/eol.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/eol.c Thu Dec 2 20:55:08 2010
@@ -84,7 +84,7 @@ svn_eol__detect_file_eol(const char **eo
err = svn_io_file_read(file, buf, &nbytes, pool);
if (err)
{
- /* An error occured. We're going to return in any case,
+ /* An error occurred. We're going to return in any case,
* so reset the file cursor right now. */
pos = orig_pos;
SVN_ERR(svn_io_file_seek(file, APR_SET, &pos, pool));
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/io.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/io.c Thu Dec 2 20:55:08 2010
@@ -334,6 +334,10 @@ svn_io_open_uniquely_named(apr_file_t **
unsigned int i;
struct temp_file_cleanup_s *baton = NULL;
+ /* At the beginning, we don't know whether unique_path will need
+ UTF8 conversion */
+ svn_boolean_t needs_utf8_conversion = TRUE;
+
SVN_ERR_ASSERT(file || unique_path);
if (dirpath == NULL)
@@ -394,7 +398,21 @@ svn_io_open_uniquely_named(apr_file_t **
before starting iteration, then convert back to UTF-8 for
return. But I suppose that would make the appending code
sensitive to i18n in a way it shouldn't be... Oh well. */
- SVN_ERR(cstring_from_utf8(&unique_name_apr, unique_name, scratch_pool));
+ if (needs_utf8_conversion)
+ {
+ SVN_ERR(cstring_from_utf8(&unique_name_apr, unique_name,
+ scratch_pool));
+ if (i == 1)
+ {
+ /* The variable parts of unique_name will not require UTF8
+ conversion. Therefore, if UTF8 conversion had no effect
+ on it in the first iteration, it won't require conversion
+ in any future interation. */
+ needs_utf8_conversion = strcmp(unique_name_apr, unique_name);
+ }
+ }
+ else
+ unique_name_apr = unique_name;
apr_err = file_open(&try_file, unique_name_apr, flag,
APR_OS_DEFAULT, FALSE, result_pool);
@@ -800,6 +818,29 @@ file_perms_set(const char *fname, apr_fi
else
return SVN_NO_ERROR;
}
+
+/* Set permissions PERMS on the FILE. This is a cheaper variant of the
+ * file_perms_set wrapper() function because no locale-dependent string
+ * conversion is required.
+ */
+static svn_error_t *
+file_perms_set2(apr_file_t* file, apr_fileperms_t perms)
+{
+ const char *fname_apr;
+ apr_status_t status;
+
+ status = apr_file_name_get(&fname_apr, file);
+ if (status)
+ return svn_error_wrap_apr(status, _("Can't get file name"));
+
+ status = apr_file_perms_set(fname_apr, perms);
+ if (status)
+ return svn_error_wrap_apr(status, _("Can't set permissions on '%s'"),
+ fname_apr);
+ else
+ return SVN_NO_ERROR;
+}
+
#endif /* !WIN32 && !__OS2__ */
svn_error_t *
@@ -1680,7 +1721,7 @@ svn_io_file_lock2(const char *lock_file,
/* Data consistency/coherency operations. */
-static svn_error_t *
+static APR_INLINE svn_error_t *
do_io_file_wrapper_cleanup(apr_file_t *file, apr_status_t status,
const char *msg, const char *msg_no_name,
apr_pool_t *pool);
@@ -2741,7 +2782,7 @@ svn_io_file_open(apr_file_t **new_file,
}
-static svn_error_t *
+static APR_INLINE svn_error_t *
do_io_file_wrapper_cleanup(apr_file_t *file, apr_status_t status,
const char *msg, const char *msg_no_name,
apr_pool_t *pool)
@@ -3273,6 +3314,10 @@ svn_io_dir_walk2(const char *dirname,
SVN_ERR(cstring_from_utf8(&dirname_apr, dirname, pool));
+ /* APR doesn't like "" directories */
+ if (dirname_apr[0] == '\0')
+ dirname_apr = ".";
+
apr_err = apr_dir_open(&handle, dirname_apr, pool);
if (apr_err)
return svn_error_wrap_apr(apr_err, _("Can't open directory '%s'"),
@@ -3836,7 +3881,7 @@ svn_io_open_unique_file3(apr_file_t **fi
* ### So we tweak perms of the tempfile here, but only if the umask
* ### allows it. */
SVN_ERR(merge_default_file_perms(tempfile, &perms, scratch_pool));
- SVN_ERR(file_perms_set(tempname, perms, scratch_pool));
+ SVN_ERR(file_perms_set2(tempfile, perms));
#endif
if (file)
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/mergeinfo.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/mergeinfo.c Thu Dec 2 20:55:08 2010
@@ -1760,7 +1760,7 @@ svn_mergeinfo__remove_prefix_from_catalo
apr_ssize_t padding = 0;
SVN_ERR_ASSERT(klen >= prefix_len);
- SVN_ERR_ASSERT(svn_uri_is_ancestor(prefix_path, original_path));
+ SVN_ERR_ASSERT(svn_fspath__is_ancestor(prefix_path, original_path));
/* If the ORIGINAL_PATH doesn't match the PREFIX_PATH exactly
and we're not simply removing a single leading slash (such as
@@ -1809,33 +1809,28 @@ svn_mergeinfo__add_prefix_to_catalog(svn
svn_error_t *
svn_mergeinfo__add_suffix_to_mergeinfo(svn_mergeinfo_t *out_mergeinfo,
svn_mergeinfo_t mergeinfo,
- const char *suffix,
+ const char *suffix_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- if (!suffix || svn_dirent_is_absolute(suffix))
- {
- *out_mergeinfo = svn_mergeinfo_dup(mergeinfo, result_pool);
- }
- else
- {
- apr_hash_index_t *hi;
- const char *canonical_suffix = svn_uri_canonicalize(suffix,
- scratch_pool);
- *out_mergeinfo = apr_hash_make(result_pool);
+ apr_hash_index_t *hi;
- for (hi = apr_hash_first(scratch_pool, mergeinfo);
- hi;
- hi = apr_hash_next(hi))
- {
- const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ SVN_ERR_ASSERT(suffix_relpath && svn_relpath_is_canonical(suffix_relpath,
+ scratch_pool));
- apr_hash_set(*out_mergeinfo,
- svn_dirent_join(path, canonical_suffix, result_pool),
- APR_HASH_KEY_STRING,
- svn_rangelist_dup(rangelist, result_pool));
- }
+ *out_mergeinfo = apr_hash_make(result_pool);
+
+ for (hi = apr_hash_first(scratch_pool, mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *path = svn__apr_hash_index_key(hi);
+ apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+
+ apr_hash_set(*out_mergeinfo,
+ svn_dirent_join(path, suffix_relpath, result_pool),
+ APR_HASH_KEY_STRING,
+ svn_rangelist_dup(rangelist, result_pool));
}
return SVN_NO_ERROR;
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/opt.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/opt.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/opt.c Thu Dec 2 20:55:08 2010
@@ -124,6 +124,84 @@ svn_opt_get_option_from_code(int code,
}
+/* Like svn_opt_get_option_from_code2(), but also, if CODE appears a second
+ * time in OPTION_TABLE with a different name, then set *LONG_ALIAS to that
+ * second name, else set it to NULL. */
+static const apr_getopt_option_t *
+get_option_from_code(const char **long_alias,
+ int code,
+ const apr_getopt_option_t *option_table,
+ const svn_opt_subcommand_desc2_t *command,
+ apr_pool_t *pool)
+{
+ const apr_getopt_option_t *i;
+ const apr_getopt_option_t *opt
+ = svn_opt_get_option_from_code2(code, option_table, command, pool);
+
+ /* Find a long alias in the table, if there is one. */
+ *long_alias = NULL;
+ for (i = option_table; i->optch; i++)
+ {
+ if (i->optch == code && i->name != opt->name)
+ {
+ *long_alias = i->name;
+ break;
+ }
+ }
+
+ return opt;
+}
+
+
+/* Print an option OPT nicely into a STRING allocated in POOL.
+ * If OPT has a single-character short form, then print OPT->name (if not
+ * NULL) as an alias, else print LONG_ALIAS (if not NULL) as an alias.
+ * If DOC is set, include the generic documentation string of OPT,
+ * localized to the current locale if a translation is available.
+ */
+static void
+format_option(const char **string,
+ const apr_getopt_option_t *opt,
+ const char *long_alias,
+ svn_boolean_t doc,
+ apr_pool_t *pool)
+{
+ char *opts;
+
+ if (opt == NULL)
+ {
+ *string = "?";
+ return;
+ }
+
+ /* We have a valid option which may or may not have a "short
+ name" (a single-character alias for the long option). */
+ if (opt->optch <= 255)
+ opts = apr_psprintf(pool, "-%c [--%s]", opt->optch, opt->name);
+ else if (long_alias)
+ opts = apr_psprintf(pool, "--%s [--%s]", opt->name, long_alias);
+ else
+ opts = apr_psprintf(pool, "--%s", opt->name);
+
+ if (opt->has_arg)
+ opts = apr_pstrcat(pool, opts, _(" ARG"), (char *)NULL);
+
+ if (doc)
+ opts = apr_psprintf(pool, "%-24s : %s", opts, _(opt->description));
+
+ *string = opts;
+}
+
+void
+svn_opt_format_option(const char **string,
+ const apr_getopt_option_t *opt,
+ svn_boolean_t doc,
+ apr_pool_t *pool)
+{
+ format_option(string, opt, NULL, doc, pool);
+}
+
+
svn_boolean_t
svn_opt_subcommand_takes_option3(const svn_opt_subcommand_desc2_t *command,
int option_code,
@@ -207,6 +285,7 @@ print_command_info2(const svn_opt_subcom
if (help)
{
const apr_getopt_option_t *option;
+ const char *long_alias;
svn_boolean_t have_options = FALSE;
SVN_ERR(svn_cmdline_fprintf(stream, pool, ": %s", _(cmd->help)));
@@ -224,16 +303,14 @@ print_command_info2(const svn_opt_subcom
}
/* convert each option code into an option */
- option =
- svn_opt_get_option_from_code2(cmd->valid_options[i],
- options_table,
- cmd, pool);
+ option = get_option_from_code(&long_alias, cmd->valid_options[i],
+ options_table, cmd, pool);
/* print the option's docstring */
if (option && option->description)
{
const char *optstr;
- svn_opt_format_option(&optstr, option, TRUE, pool);
+ format_option(&optstr, option, long_alias, TRUE, pool);
SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n",
optstr));
}
@@ -250,16 +327,14 @@ print_command_info2(const svn_opt_subcom
{
/* convert each option code into an option */
- option =
- svn_opt_get_option_from_code2(global_options[i],
- options_table,
- cmd, pool);
+ option = get_option_from_code(&long_alias, global_options[i],
+ options_table, cmd, pool);
/* print the option's docstring */
if (option && option->description)
{
const char *optstr;
- svn_opt_format_option(&optstr, option, TRUE, pool);
+ format_option(&optstr, option, long_alias, TRUE, pool);
SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n",
optstr));
}
@@ -312,36 +387,6 @@ svn_opt_print_generic_help2(const char *
svn_error_clear(err);
}
-void
-svn_opt_format_option(const char **string,
- const apr_getopt_option_t *opt,
- svn_boolean_t doc,
- apr_pool_t *pool)
-{
- char *opts;
-
- if (opt == NULL)
- {
- *string = "?";
- return;
- }
-
- /* We have a valid option which may or may not have a "short
- name" (a single-character alias for the long option). */
- if (opt->optch <= 255)
- opts = apr_psprintf(pool, "-%c [--%s]", opt->optch, opt->name);
- else
- opts = apr_psprintf(pool, "--%s", opt->name);
-
- if (opt->has_arg)
- opts = apr_pstrcat(pool, opts, _(" ARG"), (char *)NULL);
-
- if (doc)
- opts = apr_psprintf(pool, "%-24s : %s", opts, _(opt->description));
-
- *string = opts;
-}
-
void
svn_opt_subcommand_help3(const char *subcommand,
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/subst.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/subst.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/subst.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/subst.c Thu Dec 2 20:55:08 2010
@@ -798,6 +798,10 @@ struct translation_baton
/* Length of the EOL style string found in the chunk-source,
or zero if none encountered yet */
apr_size_t src_format_len;
+
+ /* If this is svn_tristate_false, translate_newline() will be called
+ for every newline in the file */
+ svn_tristate_t nl_translation_skippable;
};
@@ -828,6 +832,7 @@ create_translation_baton(const char *eol
b->newline_off = 0;
b->keyword_off = 0;
b->src_format_len = 0;
+ b->nl_translation_skippable = svn_tristate_unknown;
/* Most characters don't start translation actions.
* Mark those that do depending on the parameters we got. */
@@ -843,6 +848,38 @@ create_translation_baton(const char *eol
return b;
}
+/* Return TRUE if the EOL starting at BUF matches the eol_str member of B.
+ * Be aware of special cases like "\n\r\n" and "\n\n\r". For sequences like
+ * "\n$" (an EOL followed by a keyword), the result will be FALSE since it is
+ * more efficient to handle that special case implicitly in the calling code
+ * by exiting the quick scan loop.
+ * The caller must ensure that buf[0] and buf[1] refer to valid memory
+ * locations.
+ */
+static APR_INLINE svn_boolean_t
+eol_unchanged(struct translation_baton *b,
+ const char *buf)
+{
+ /* If the first byte doesn't match, the whole EOL won't.
+ * This does also handle the (certainly invalid) case that
+ * eol_str would be an empty string.
+ */
+ if (buf[0] != b->eol_str[0])
+ return FALSE;
+
+ /* two-char EOLs must be a full match */
+ if (b->eol_str_len == 2)
+ return buf[1] == b->eol_str[1];
+
+ /* The first char matches the required 1-byte EOL.
+ * But maybe, buf[] contains a 2-byte EOL?
+ * In that case, the second byte will be interesting
+ * and not be another EOL of its own.
+ */
+ return !b->interesting[(unsigned char)buf[1]] || buf[0] == buf[1];
+}
+
+
/* Translate eols and keywords of a 'chunk' of characters BUF of size BUFLEN
* according to the settings and state stored in baton B.
*
@@ -948,19 +985,72 @@ translate_chunk(svn_stream_t *dst,
continue;
}
- /* We're in the boring state; look for interest characters. */
- len = 0;
+ /* translate_newline will modify the baton for src_format_len==0
+ or may return an error if b->repair is FALSE. In all other
+ cases, we can skip the newline translation as long as source
+ EOL format and actual EOL format match. If there is a
+ mismatch, translate_newline will be called regardless of
+ nl_translation_skippable.
+ */
+ if (b->nl_translation_skippable == svn_tristate_unknown &&
+ b->src_format_len > 0)
+ {
+ /* test whether translate_newline may return an error */
+ if (b->eol_str_len == b->src_format_len &&
+ strncmp(b->eol_str, b->src_format, b->eol_str_len) == 0)
+ b->nl_translation_skippable = svn_tristate_true;
+ else if (b->repair)
+ b->nl_translation_skippable = svn_tristate_true;
+ else
+ b->nl_translation_skippable = svn_tristate_false;
+ }
+
+ /* We're in the boring state; look for interesting characters.
+ Offset len such that it will become 0 in the first iteration.
+ */
+ len = 0 - b->eol_str_len;
+
+ /* Look for the next EOL (or $) that actually needs translation.
+ Stop there or at EOF, whichever is encountered first.
+ */
+ do
+ {
+ /* 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)
+ {
+ char sum = interesting[(unsigned char)p[len]]
+ | interesting[(unsigned char)p[len+1]]
+ | interesting[(unsigned char)p[len+2]]
+ | interesting[(unsigned char)p[len+3]];
+
+ if (sum != 0)
+ 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;
+ }
+ 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 */
- /* We wanted memcspn(), but lacking that, the loop below has
- the same effect. Also, skip NUL characters.
- */
while ((p + len) < end && !interesting[(unsigned char)p[len]])
len++;
if (len)
- SVN_ERR(translate_write(dst, p, len));
-
- p += len;
+ {
+ SVN_ERR(translate_write(dst, p, len));
+ p += len;
+ }
/* Set up state according to the interesting character, if any. */
if (p < end)
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/svn_string.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/svn_string.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/svn_string.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_subr/svn_string.c Thu Dec 2 20:55:08 2010
@@ -250,7 +250,15 @@ create_stringbuf(char *data, apr_size_t
svn_stringbuf_t *
svn_stringbuf_create_ensure(apr_size_t blocksize, apr_pool_t *pool)
{
- char *data = apr_palloc(pool, ++blocksize); /* + space for '\0' */
+ char *data;
+
+ /* 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. */
+
+ ++blocksize; /* + space for '\0' */
+ data = apr_palloc(pool, APR_ALIGN_DEFAULT(blocksize));
data[0] = '\0';
@@ -261,9 +269,7 @@ svn_stringbuf_create_ensure(apr_size_t b
svn_stringbuf_t *
svn_stringbuf_ncreate(const char *bytes, apr_size_t size, apr_pool_t *pool)
{
- /* Ensure string buffer of size + 1 */
svn_stringbuf_t *strbuf = svn_stringbuf_create_ensure(size, pool);
-
memcpy(strbuf->data, bytes, size);
/* Null termination is the convention -- even if we suspect the data
@@ -368,12 +374,18 @@ svn_stringbuf_ensure(svn_stringbuf_t *st
if (str->blocksize < minimum_size)
{
if (str->blocksize == 0)
- str->blocksize = minimum_size;
+ /* APR will increase odd allocation sizes to the next
+ * multiple for 8, for instance. Take advantage of that
+ * knowledge and allow for the extra size to be used. */
+ str->blocksize = APR_ALIGN_DEFAULT(minimum_size);
else
while (str->blocksize < minimum_size)
{
+ /* str->blocksize is aligned;
+ * doubling it should keep it aligned */
apr_size_t prev_size = str->blocksize;
str->blocksize *= 2;
+
/* check for apr_size_t overflow */
if (prev_size > str->blocksize)
{
@@ -406,7 +418,7 @@ svn_stringbuf_appendbyte(svn_stringbuf_t
* to just write the new byte at the end of the used section
* and terminate the string properly.
*/
- if (str->blocksize < old_len + 1)
+ if (str->blocksize > old_len + 1)
{
/* The following read does not depend this write, so we
* can issue the write first to minimize register pressure:
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_crawler.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_crawler.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_crawler.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_crawler.c Thu Dec 2 20:55:08 2010
@@ -347,7 +347,8 @@ report_revisions_and_depths(svn_wc__db_t
svn_revnum_t this_rev;
svn_depth_t this_depth;
svn_wc__db_lock_t *this_lock;
- svn_boolean_t this_switched;
+ svn_boolean_t this_switched = FALSE;
+ svn_boolean_t this_file_external = FALSE;
/* Clear the iteration subpool here because the loop has a bunch
of 'continue' jump statements. */
@@ -461,7 +462,6 @@ report_revisions_and_depths(svn_wc__db_t
/* And finally prepare for reporting */
if (!this_repos_relpath)
{
- this_switched = FALSE;
this_repos_relpath = svn_relpath_join(dir_repos_relpath, child,
iterpool);
}
@@ -472,9 +472,20 @@ report_revisions_and_depths(svn_wc__db_t
NULL);
if (childname == NULL || strcmp(childname, child) != 0)
- this_switched = TRUE;
- else
- this_switched = FALSE;
+ {
+ const char *file_ext_str;
+
+ this_switched = TRUE;
+
+ /* This could be a file external! We need to know
+ that. */
+ SVN_ERR(svn_wc__db_temp_get_file_external(&file_ext_str, db,
+ this_abspath,
+ scratch_pool,
+ scratch_pool));
+ if (file_ext_str)
+ this_file_external = TRUE;
+ }
}
/* Tweak THIS_DEPTH to a useful value. */
@@ -489,9 +500,15 @@ report_revisions_and_depths(svn_wc__db_t
if (!SVN_IS_VALID_REVNUM(this_rev))
this_rev = dir_rev;
+ /*** File Externals **/
+ if (this_file_external)
+ {
+ /* File externals are ... special. We ignore them. */;
+ }
+
/*** Files ***/
- if (this_kind == svn_wc__db_kind_file ||
- this_kind == svn_wc__db_kind_symlink)
+ else if (this_kind == svn_wc__db_kind_file ||
+ this_kind == svn_wc__db_kind_symlink)
{
if (report_everything)
{
@@ -563,7 +580,7 @@ report_revisions_and_depths(svn_wc__db_t
if (report_everything)
{
- /* Report the dir unconditionally, one way or another. */
+ /* Report the dir unconditionally, one way or another... */
if (this_switched)
SVN_ERR(reporter->link_path(report_baton,
this_path,
@@ -585,24 +602,20 @@ report_revisions_and_depths(svn_wc__db_t
this_lock ? this_lock->token : NULL,
iterpool));
}
-
- /* Possibly report a disjoint URL ... */
else if (this_switched)
- SVN_ERR(reporter->link_path(report_baton,
- this_path,
- svn_path_url_add_component2(
- dir_repos_root,
- this_repos_relpath, iterpool),
- this_rev,
- this_depth,
- start_empty,
- this_lock ? this_lock->token : NULL,
- iterpool));
- /* ... or perhaps just a differing revision, lock token, incomplete
- subdir, the mere presence of the directory in a depth-empty or
- depth-files dir, or if the parent dir is at depth-immediates but
- the child is not at depth-empty. Also describe shallow subdirs
- if we are trying to set depth to infinity. */
+ {
+ /* ...or possibly report a disjoint URL ... */
+ SVN_ERR(reporter->link_path(report_baton,
+ this_path,
+ svn_path_url_add_component2(
+ dir_repos_root,
+ this_repos_relpath, iterpool),
+ this_rev,
+ this_depth,
+ start_empty,
+ this_lock ? this_lock->token : NULL,
+ iterpool));
+ }
else if (this_rev != dir_rev
|| this_lock
|| is_incomplete
@@ -612,16 +625,25 @@ report_revisions_and_depths(svn_wc__db_t
&& this_depth != svn_depth_empty)
|| (this_depth < svn_depth_infinity
&& depth == svn_depth_infinity))
- SVN_ERR(reporter->set_path(report_baton,
- this_path,
- this_rev,
- this_depth,
- start_empty,
- this_lock ? this_lock->token : NULL,
- iterpool));
+ {
+ /* ... or perhaps just a differing revision, lock token,
+ incomplete subdir, the mere presence of the directory
+ in a depth-empty or depth-files dir, or if the parent
+ dir is at depth-immediates but the child is not at
+ depth-empty. Also describe shallow subdirs if we are
+ trying to set depth to infinity. */
+ SVN_ERR(reporter->set_path(report_baton,
+ this_path,
+ this_rev,
+ this_depth,
+ start_empty,
+ this_lock ? this_lock->token : NULL,
+ iterpool));
+ }
+ /* Finally, recurse if necessary and appropriate. */
if (SVN_DEPTH_IS_RECURSIVE(depth))
- SVN_ERR(report_revisions_and_depths(db,
+ SVN_ERR(report_revisions_and_depths(db,
anchor_abspath,
this_path,
this_rev,
@@ -792,22 +814,12 @@ svn_wc_crawl_revisions5(svn_wc_context_t
if (!repos_root || !repos_relpath)
{
- err = svn_wc__db_scan_base_repos(&repos_relpath, &repos_root, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool);
-
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
- svn_error_clear(err);
- else
- SVN_ERR(err);
-
/* Ok, that leaves a local addition. Deleted and not existing nodes
are already handled. */
- if (!repos_root || !repos_relpath)
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &repos_relpath,
- &repos_root, NULL, NULL, NULL, NULL,
- NULL, db, local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &repos_relpath,
+ &repos_root, NULL, NULL, NULL, NULL,
+ NULL, db, local_abspath,
+ scratch_pool, scratch_pool));
}
if (!SVN_IS_VALID_REVNUM(target_rev))
@@ -925,15 +937,6 @@ svn_wc_crawl_revisions5(svn_wc_context_t
if (err)
goto abort_report;
- if (!parent_repos_relpath)
- err = svn_wc__db_scan_base_repos(&parent_repos_relpath, NULL,
- NULL,
- db, parent_abspath,
- scratch_pool, scratch_pool);
-
- if (err)
- goto abort_report;
-
if (strcmp(repos_relpath,
svn_relpath_join(parent_repos_relpath, base,
scratch_pool)) != 0)
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_files.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_files.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_files.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_files.c Thu Dec 2 20:55:08 2010
@@ -774,7 +774,6 @@ svn_wc_create_tmp_file2(apr_file_t **fp,
svn_wc__db_t *db;
const char *local_abspath;
const char *temp_dir;
- apr_file_t *file;
svn_error_t *err;
SVN_ERR_ASSERT(fp || new_name);
@@ -792,14 +791,9 @@ svn_wc_create_tmp_file2(apr_file_t **fp,
if (err)
return svn_error_return(err);
- SVN_ERR(svn_io_open_unique_file3(&file, new_name, temp_dir,
+ SVN_ERR(svn_io_open_unique_file3(fp, new_name, temp_dir,
delete_when, pool, pool));
- if (fp)
- *fp = file;
- else
- SVN_ERR(svn_io_file_close(file, pool));
-
return SVN_NO_ERROR;
}
Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_ops.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_wc/adm_ops.c Thu Dec 2 20:55:08 2010
@@ -735,28 +735,127 @@ svn_wc_delete4(svn_wc_context_t *wc_ctx,
return SVN_NO_ERROR;
}
-svn_error_t *
-svn_wc_add4(svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- svn_depth_t depth,
- const char *copyfrom_url,
- svn_revnum_t copyfrom_rev,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
- apr_pool_t *scratch_pool)
+/* Schedule the single node at LOCAL_ABSPATH, of kind KIND, for addition in
+ * its parent directory in the WC. It will have no properties. */
+static svn_error_t *
+add_from_disk(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_node_kind_t kind,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_t *db = wc_ctx->db;
+
+ if (kind == svn_node_file)
+ {
+ SVN_ERR(svn_wc__db_op_add_file(db, local_abspath, NULL, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(svn_wc__db_op_add_directory(db, local_abspath, NULL,
+ scratch_pool));
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Set *REPOS_ROOT_URL and *REPOS_UUID to the repository of the parent of
+ LOCAL_ABSPATH. REPOS_ROOT_URL and/or REPOS_UUID may be NULL if not
+ wanted. Check that the parent of LOCAL_ABSPATH is a versioned directory
+ in a state in which a new child node can be scheduled for addition;
+ return an error if not. */
+static svn_error_t *
+check_can_add_to_parent(const char **repos_root_url,
+ const char **repos_uuid,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const char *parent_abspath;
- const char *base_name;
- const char *parent_repos_relpath;
- const char *repos_root_url, *repos_uuid;
- svn_boolean_t is_wc_root = FALSE;
- svn_node_kind_t kind;
svn_wc__db_t *db = wc_ctx->db;
+ const char *parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+ svn_wc__db_status_t parent_status;
+ svn_wc__db_kind_t parent_kind;
svn_error_t *err;
- svn_wc__db_status_t status;
- svn_wc__db_kind_t db_kind;
+
+ SVN_ERR(svn_wc__write_check(db, parent_abspath, scratch_pool));
+
+ err = svn_wc__db_read_info(&parent_status, &parent_kind, NULL,
+ NULL, repos_root_url,
+ repos_uuid, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ db, parent_abspath, result_pool, scratch_pool);
+
+ if (err
+ || parent_status == svn_wc__db_status_not_present
+ || parent_status == svn_wc__db_status_excluded
+ || parent_status == svn_wc__db_status_absent)
+ {
+ return
+ svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, err,
+ _("Can't find parent directory's node while"
+ " trying to add '%s'"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ else if (parent_status == svn_wc__db_status_deleted)
+ {
+ return
+ svn_error_createf(SVN_ERR_WC_SCHEDULE_CONFLICT, NULL,
+ _("Can't add '%s' to a parent directory"
+ " scheduled for deletion"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ else if (parent_kind != svn_wc__db_kind_dir)
+ return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Can't schedule an addition of '%s'"
+ " below a not-directory node"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ /* If we haven't found the repository info yet, find it now. */
+ if ((repos_root_url && ! *repos_root_url)
+ || (repos_uuid && ! *repos_uuid))
+ {
+ if (parent_status == svn_wc__db_status_added)
+ SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL,
+ repos_root_url, repos_uuid, NULL,
+ NULL, NULL, NULL,
+ db, parent_abspath,
+ result_pool, scratch_pool));
+ else
+ SVN_ERR(svn_wc__db_scan_base_repos(NULL,
+ repos_root_url, repos_uuid,
+ db, parent_abspath,
+ result_pool, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Check that the on-disk item at LOCAL_ABSPATH can be scheduled for
+ * addition to its WC parent directory.
+ *
+ * Set *KIND_P to the kind of node to be added, *DB_ROW_EXISTS_P to whether
+ * it is already a versioned path, and if so, *IS_WC_ROOT_P to whether it's
+ * a WC root.
+ *
+ * ### The checks here, and the outputs, are geared towards svn_wc_add4().
+ */
+static svn_error_t *
+check_can_add_node(svn_node_kind_t *kind_p,
+ svn_boolean_t *db_row_exists_p,
+ svn_boolean_t *is_wc_root_p,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ const char *copyfrom_url,
+ svn_revnum_t copyfrom_rev,
+ apr_pool_t *scratch_pool)
+{
+ const char *base_name = svn_dirent_basename(local_abspath, scratch_pool);
+ svn_boolean_t is_wc_root;
+ svn_node_kind_t kind;
+ svn_wc__db_t *db = wc_ctx->db;
svn_boolean_t exists;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -764,7 +863,7 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
scratch_pool)
&& SVN_IS_VALID_REVNUM(copyfrom_rev)));
- svn_dirent_split(&parent_abspath, &base_name, local_abspath, scratch_pool);
+ /* Check that the proposed node has an acceptable name. */
if (svn_wc_is_adm_dir(base_name, scratch_pool))
return svn_error_createf
(SVN_ERR_ENTRY_FORBIDDEN, NULL,
@@ -773,7 +872,7 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
SVN_ERR(svn_path_check_valid(local_abspath, scratch_pool));
- /* Make sure something's there. */
+ /* Make sure something's there; set KIND and *KIND_P. */
SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
@@ -785,123 +884,170 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
_("Unsupported node kind for path '%s'"),
svn_dirent_local_style(local_abspath,
scratch_pool));
+ if (kind_p)
+ *kind_p = kind;
- /* Get the node information for this path if one exists (perhaps
- this is actually a replacement of a previously deleted thing). */
- err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
+ /* Determine whether a DB row for this node EXISTS, and whether it
+ IS_WC_ROOT. If it exists, check that it is in an acceptable state for
+ adding the new node; if not, return an error. */
+ {
+ svn_wc__db_status_t status;
+ svn_error_t *err
+ = svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool);
- if (err)
- {
- if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
- return svn_error_return(err);
+ if (err)
+ {
+ if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+ return svn_error_return(err);
- svn_error_clear(err);
- exists = FALSE;
- is_wc_root = FALSE;
- }
- else
- {
- is_wc_root = FALSE;
- exists = TRUE;
- switch (status)
- {
- case svn_wc__db_status_not_present:
- break;
- case svn_wc__db_status_deleted:
- /* A working copy root should never have a WORKING_NODE */
- SVN_ERR_ASSERT(!is_wc_root);
- break;
- case svn_wc__db_status_normal:
- if (copyfrom_url)
- {
- SVN_ERR(svn_wc__check_wc_root(&is_wc_root, NULL, NULL,
- db, local_abspath,
- scratch_pool));
+ svn_error_clear(err);
+ exists = FALSE;
+ is_wc_root = FALSE;
+ }
+ else
+ {
+ is_wc_root = FALSE;
+ exists = TRUE;
+ switch (status)
+ {
+ case svn_wc__db_status_not_present:
+ break;
+ case svn_wc__db_status_deleted:
+ /* A working copy root should never have a WORKING_NODE */
+ SVN_ERR_ASSERT(!is_wc_root);
+ break;
+ case svn_wc__db_status_normal:
+ if (copyfrom_url)
+ {
+ SVN_ERR(svn_wc__check_wc_root(&is_wc_root, NULL, NULL,
+ db, local_abspath,
+ scratch_pool));
- if (is_wc_root)
- break;
- }
- /* else: Fall through in default error */
+ if (is_wc_root)
+ break;
+ }
+ /* else: Fall through in default error */
- default:
- return svn_error_createf(
- SVN_ERR_ENTRY_EXISTS, NULL,
- _("'%s' is already under version control"),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
- }
- } /* err */
+ default:
+ return svn_error_createf(
+ SVN_ERR_ENTRY_EXISTS, NULL,
+ _("'%s' is already under version control"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ } /* err */
- SVN_ERR(svn_wc__write_check(db, parent_abspath, scratch_pool));
+ if (db_row_exists_p)
+ *db_row_exists_p = exists;
+ if (is_wc_root_p)
+ *is_wc_root_p = is_wc_root;
+ }
- {
- svn_wc__db_status_t parent_status;
- svn_wc__db_kind_t parent_kind;
+ return SVN_NO_ERROR;
+}
- err = svn_wc__db_read_info(&parent_status, &parent_kind, NULL,
- &parent_repos_relpath, &repos_root_url,
- &repos_uuid, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- db, parent_abspath, scratch_pool, scratch_pool);
+/* Convert the nested pristine working copy rooted at LOCAL_ABSPATH into
+ * a copied subtree in the outer working copy.
+ *
+ * LOCAL_ABSPATH must be the root of a nested working copy that has no
+ * local modifications. The parent directory of LOCAL_ABSPATH must be a
+ * versioned directory in the outer WC, and must belong to the same
+ * repository as the nested WC. The nested WC will be integrated into the
+ * parent's WC, and will no longer be a separate WC. */
+static svn_error_t *
+integrate_nested_wc_as_copy(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_t *db = wc_ctx->db;
+ const char *moved_abspath;
- if (err
- || parent_status == svn_wc__db_status_not_present
- || parent_status == svn_wc__db_status_excluded
- || parent_status == svn_wc__db_status_absent)
- {
- return
- svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, err,
- _("Can't find parent directory's node while"
- " trying to add '%s'"),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
- }
- else if (parent_status == svn_wc__db_status_deleted)
- {
- return
- svn_error_createf(SVN_ERR_WC_SCHEDULE_CONFLICT, NULL,
- _("Can't add '%s' to a parent directory"
- " scheduled for deletion"),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
- }
- else if (parent_kind != svn_wc__db_kind_dir)
- /* Can't happen until single db; but then it causes serious
- trouble if we allow this. */
- return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
- _("Can't schedule an addition of '%s'"
- " below a not-directory node"),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
+ /* Drop any references to the wc that is to be rewritten */
+ SVN_ERR(svn_wc__db_drop_root(db, local_abspath, scratch_pool));
- if (!repos_root_url)
- {
- if (parent_status == svn_wc__db_status_added)
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &parent_repos_relpath,
- &repos_root_url, &repos_uuid, NULL,
- NULL, NULL, NULL,
- db, parent_abspath,
+ /* Move the admin dir from the wc to a temporary location: MOVED_ABSPATH */
+ {
+ const char *tmpdir_abspath, *moved_adm_abspath, *adm_abspath;
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db,
+ svn_dirent_dirname(local_abspath,
+ scratch_pool),
scratch_pool, scratch_pool));
- else
- SVN_ERR(svn_wc__db_scan_base_repos(&parent_repos_relpath,
- &repos_root_url, &repos_uuid,
- db, parent_abspath,
- scratch_pool, scratch_pool));
- }
+ SVN_ERR(svn_io_open_unique_file3(NULL, &moved_abspath, tmpdir_abspath,
+ svn_io_file_del_on_close,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_io_dir_make(moved_abspath, APR_OS_DEFAULT, scratch_pool));
+
+ adm_abspath = svn_wc__adm_child(local_abspath, "", scratch_pool);
+ moved_adm_abspath = svn_wc__adm_child(moved_abspath, "", scratch_pool);
+ SVN_ERR(svn_io_file_move(adm_abspath, moved_adm_abspath, scratch_pool));
+ }
- if (copyfrom_url
- && !svn_uri_is_ancestor(repos_root_url, copyfrom_url))
- return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
- _("The URL '%s' has a different repository "
- "root than its parent"), copyfrom_url);
+ /* Copy entries from temporary location into the main db */
+ SVN_ERR(svn_wc_copy3(wc_ctx, moved_abspath, local_abspath,
+ TRUE /* metadata_only */,
+ NULL, NULL, NULL, NULL, scratch_pool));
+
+ /* Cleanup the temporary admin dir */
+ SVN_ERR(svn_wc__db_drop_root(db, moved_abspath, scratch_pool));
+ SVN_ERR(svn_io_remove_dir2(moved_abspath, FALSE, NULL, NULL,
+ scratch_pool));
+
+ /* The subdir is now part of our parent working copy. Our caller assumes
+ that we return the new node locked, so obtain a lock if we didn't
+ receive the lock via our depth infinity lock */
+ {
+ svn_boolean_t owns_lock;
+ SVN_ERR(svn_wc__db_wclock_owns_lock(&owns_lock, db, local_abspath,
+ FALSE, scratch_pool));
+ if (!owns_lock)
+ SVN_ERR(svn_wc__db_wclock_obtain(db, local_abspath, 0, FALSE,
+ scratch_pool));
}
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc_add4(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_depth_t depth,
+ const char *copyfrom_url,
+ svn_revnum_t copyfrom_rev,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_t *db = wc_ctx->db;
+ svn_node_kind_t kind;
+ svn_boolean_t db_row_exists, is_wc_root;
+ const char *repos_root_url, *repos_uuid;
+
+ SVN_ERR(check_can_add_node(&kind, &db_row_exists, &is_wc_root,
+ wc_ctx, local_abspath, copyfrom_url, copyfrom_rev,
+ scratch_pool));
+
+ /* Get REPOS_ROOT_URL and REPOS_UUID. Check that the
+ parent is a versioned directory in an acceptable state. */
+ SVN_ERR(check_can_add_to_parent(&repos_root_url, &repos_uuid,
+ wc_ctx, local_abspath, scratch_pool,
+ scratch_pool));
+
+ /* If we're performing a repos-to-WC copy, check that the copyfrom
+ repository is the same as the parent dir's repository. */
+ if (copyfrom_url
+ && !svn_uri_is_ancestor(repos_root_url, copyfrom_url))
+ return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("The URL '%s' has a different repository "
+ "root than its parent"), copyfrom_url);
+
/* Verify that we can actually integrate the inner working copy */
if (is_wc_root)
{
@@ -926,13 +1072,8 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
inner_repos_root_url, inner_repos_uuid,
repos_root_url, repos_uuid);
- if (!svn_uri_is_ancestor(repos_root_url, copyfrom_url))
- return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
- _("The URL '%s' is not in repository '%s'"),
- copyfrom_url, repos_root_url);
-
inner_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- scratch_pool);
+ scratch_pool);
if (strcmp(copyfrom_url, inner_url))
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
@@ -943,11 +1084,27 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
copyfrom_url, inner_url);
}
- if (kind == svn_node_file)
+ if (!copyfrom_url) /* Case 2a: It's a simple add */
{
- if (!copyfrom_url)
- SVN_ERR(svn_wc__db_op_add_file(db, local_abspath, NULL, scratch_pool));
- else
+ SVN_ERR(add_from_disk(wc_ctx, local_abspath, kind, scratch_pool));
+ if (kind == svn_node_dir && !db_row_exists)
+ {
+ /* If using the legacy 1.6 interface the parent lock may not
+ be recursive and add is expected to lock the new dir.
+
+ ### Perhaps the lock should be created in the same
+ transaction that adds the node? */
+ svn_boolean_t owns_lock;
+ SVN_ERR(svn_wc__db_wclock_owns_lock(&owns_lock, db, local_abspath,
+ FALSE, scratch_pool));
+ if (!owns_lock)
+ SVN_ERR(svn_wc__db_wclock_obtain(db, local_abspath, 0, FALSE,
+ scratch_pool));
+ }
+ }
+ else if (!is_wc_root) /* Case 2b: It's a copy from the repository */
+ {
+ if (kind == svn_node_file)
{
/* This code should never be used, as it doesn't install proper
pristine and/or properties. But it was not an error in the old
@@ -957,93 +1114,60 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
svn_stream_t *content = svn_stream_empty(scratch_pool);
SVN_ERR(svn_wc_add_repos_file4(wc_ctx, local_abspath,
- content, NULL,
- NULL, NULL,
+ content, NULL, NULL, NULL,
copyfrom_url, copyfrom_rev,
cancel_func, cancel_baton,
- NULL, NULL,
scratch_pool));
}
+ else
+ SVN_ERR(svn_wc__db_op_copy_dir(db, local_abspath,
+ apr_hash_make(scratch_pool),
+ copyfrom_rev, 0, NULL,
+ svn_path_uri_decode(
+ svn_uri_skip_ancestor(repos_root_url,
+ copyfrom_url),
+ scratch_pool),
+ repos_root_url, repos_uuid,
+ copyfrom_rev,
+ NULL /* children */, depth,
+ NULL /* conflicts */,
+ NULL /* work items */,
+ scratch_pool));
}
- else if (!copyfrom_url)
+ else /* Case 1: Integrating a separate WC into this one, in place */
{
- SVN_ERR(svn_wc__db_op_add_directory(db, local_abspath, NULL,
+ SVN_ERR(integrate_nested_wc_as_copy(wc_ctx, local_abspath,
scratch_pool));
- if (!exists)
- {
- /* If using the legacy 1.6 interface the parent lock may not
- be recursive and add is expected to lock the new dir.
-
- ### Perhaps the lock should be created in the same
- transaction that adds the node? */
- svn_boolean_t owns_lock;
- SVN_ERR(svn_wc__db_wclock_owns_lock(&owns_lock, db, local_abspath,
- FALSE, scratch_pool));
- if (!owns_lock)
- SVN_ERR(svn_wc__db_wclock_obtain(db, local_abspath, 0, FALSE,
- scratch_pool));
- }
}
- else if (!is_wc_root)
- SVN_ERR(svn_wc__db_op_copy_dir(db,
- local_abspath,
- apr_hash_make(scratch_pool),
- copyfrom_rev,
- 0,
- NULL,
- svn_path_uri_decode(
- svn_uri_skip_ancestor(repos_root_url,
- copyfrom_url),
- scratch_pool),
- repos_root_url,
- repos_uuid,
- copyfrom_rev,
- NULL,
- depth,
- NULL,
- NULL,
- scratch_pool));
- else
+
+ /* Report the addition to the caller. */
+ if (notify_func != NULL)
{
- svn_boolean_t owns_lock;
- const char *tmpdir_abspath, *moved_abspath, *moved_adm_abspath;
- const char *adm_abspath = svn_wc__adm_child(local_abspath, "",
- scratch_pool);
-
- /* Drop any references to the wc that is to be rewritten */
- SVN_ERR(svn_wc__db_drop_root(db, local_abspath, scratch_pool));
-
- /* Move the admin dir from the wc to a temporary location */
- SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db,
- parent_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_io_open_unique_file3(NULL, &moved_abspath, tmpdir_abspath,
- svn_io_file_del_on_close,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_io_dir_make(moved_abspath, APR_OS_DEFAULT, scratch_pool));
- moved_adm_abspath = svn_wc__adm_child(moved_abspath, "", scratch_pool);
- SVN_ERR(svn_io_file_move(adm_abspath, moved_adm_abspath, scratch_pool));
-
- /* Copy entries from temporary location into the main db */
- SVN_ERR(svn_wc_copy3(wc_ctx, moved_abspath, local_abspath,
- TRUE /* metadata_only */,
- NULL, NULL, NULL, NULL, scratch_pool));
-
- /* Cleanup the temporary admin dir */
- SVN_ERR(svn_wc__db_drop_root(db, moved_abspath, scratch_pool));
- SVN_ERR(svn_io_remove_dir2(moved_abspath, FALSE, NULL, NULL,
- scratch_pool));
-
- /* The subdir is now part of our parent working copy. Our caller assumes
- that we return the new node locked, so obtain a lock if we didn't
- receive the lock via our depth infinity lock */
- SVN_ERR(svn_wc__db_wclock_owns_lock(&owns_lock, db, local_abspath, FALSE,
- scratch_pool));
- if (!owns_lock)
- SVN_ERR(svn_wc__db_wclock_obtain(db, local_abspath, 0, FALSE,
- scratch_pool));
+ svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath,
+ svn_wc_notify_add,
+ scratch_pool);
+ notify->kind = kind;
+ (*notify_func)(notify_baton, notify, scratch_pool);
}
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc_add_from_disk(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t kind;
+
+ SVN_ERR(check_can_add_node(&kind, NULL, NULL, wc_ctx, local_abspath,
+ NULL, SVN_INVALID_REVNUM, scratch_pool));
+ SVN_ERR(check_can_add_to_parent(NULL, NULL, wc_ctx, local_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(add_from_disk(wc_ctx, local_abspath, kind, scratch_pool));
+
/* Report the addition to the caller. */
if (notify_func != NULL)
{
@@ -1133,193 +1257,6 @@ svn_wc__register_file_external(svn_wc_co
*/
-/* */
-static svn_error_t *
-revert_admin_things(svn_boolean_t *reverted,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_boolean_t use_commit_times,
- apr_pool_t *pool)
-{
- SVN_ERR(svn_wc__wq_add_revert(reverted, db, local_abspath, use_commit_times,
- pool));
- SVN_ERR(svn_wc__wq_run(db, local_abspath, NULL, NULL, pool));
-
- return SVN_NO_ERROR;
-}
-
-
-/* Revert LOCAL_ABSPATH in DB, where the on-disk node kind is DISK_KIND.
- *DEPTH is the depth of the reversion crawl the caller is
- using; this function may choose to override that value as needed.
-
- See svn_wc_revert4() for the interpretations of
- USE_COMMIT_TIMES, CANCEL_FUNC and CANCEL_BATON.
-
- Set *DID_REVERT to true if actually reverting anything, else do not
- touch *DID_REVERT.
-
- Use POOL for allocations.
- */
-static svn_error_t *
-revert_entry(svn_depth_t *depth,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_node_kind_t disk_kind,
- svn_boolean_t use_commit_times,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- svn_boolean_t *did_revert,
- apr_pool_t *pool)
-{
- svn_wc__db_status_t status, base_status;
- svn_wc__db_kind_t kind, base_kind;
- svn_boolean_t replaced;
- svn_boolean_t have_base;
- svn_revnum_t base_revision;
- svn_boolean_t is_add_root;
-
- /* Initialize this even though revert_admin_things() is guaranteed
- to set it, because we don't know that revert_admin_things() will
- be called. */
- svn_boolean_t reverted = FALSE;
-
- SVN_ERR(svn_wc__db_read_info(&status, &kind,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, &have_base, NULL,
- NULL, NULL,
- db, local_abspath, pool, pool));
-
- if (have_base)
- SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, &base_revision,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- db, local_abspath, pool, pool));
-
- replaced = (status == svn_wc__db_status_added
- && have_base
- && base_status != svn_wc__db_status_not_present);
-
- if (status == svn_wc__db_status_added)
- {
- const char *op_root_abspath;
- SVN_ERR(svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- db, local_abspath, pool, pool));
-
- is_add_root = (strcmp(op_root_abspath, local_abspath) == 0);
- }
- else
- is_add_root = FALSE;
-
- /* Additions. */
- if (!replaced
- && is_add_root)
- {
- const char *repos_relpath;
- const char *repos_root_url;
- const char *repos_uuid;
- /* Before removing item from revision control, notice if the
- BASE_NODE is in a 'not-present' state. */
- svn_boolean_t was_not_present = FALSE;
-
- /* NOTE: if WAS_NOT_PRESENT gets set, then we have BASE nodes.
- The code below will then figure out the repository information, so
- that we can later insert a node for the same repository. */
-
- if (have_base
- && base_status == svn_wc__db_status_not_present)
- {
- /* Remember the BASE revision. (already handled) */
- /* Remember the repository this node is associated with. */
-
- was_not_present = TRUE;
-
- SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath,
- &repos_root_url,
- &repos_uuid,
- db, local_abspath,
- pool, pool));
- }
-
- /* ### much of this is probably bullshit. we should be able to just
- ### remove the WORKING and ACTUAL rows, and be done. but we're
- ### not quite there yet, so nodes get fully removed and then
- ### shoved back into the database. this is why we need to record
- ### the repository information, and the BASE revision. */
-
- if (kind == svn_wc__db_kind_file)
- {
- SVN_ERR(svn_wc__internal_remove_from_revision_control(db,
- local_abspath,
- FALSE, FALSE,
- cancel_func,
- cancel_baton,
- pool));
- }
- else if (kind == svn_wc__db_kind_dir)
- {
- /* Before single-db we didn't have to perform a recursive delete
- here. With single-db we really must delete missing nodes */
- SVN_ERR(svn_wc__internal_remove_from_revision_control(db,
- local_abspath,
- FALSE, FALSE,
- cancel_func,
- cancel_baton,
- pool));
- }
- else /* Else it's `none', or something exotic like a symlink... */
- {
- return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
- _("Unknown or unexpected kind for path "
- "'%s'"),
- svn_dirent_local_style(local_abspath,
- pool));
-
- }
-
- /* Recursivity is taken care of by svn_wc_remove_from_revision_control,
- and we've definitely reverted PATH at this point. */
- *depth = svn_depth_empty;
- reverted = TRUE;
-
- /* If the removed item was *also* in a 'not-present' state, make
- sure we leave a not-present node behind */
- if (was_not_present)
- {
- SVN_ERR(svn_wc__db_base_add_not_present_node(
- db, local_abspath,
- repos_relpath, repos_root_url, repos_uuid,
- base_revision,
- base_kind,
- NULL, NULL,
- pool));
- }
- }
- /* Regular prop and text edit. */
- /* Deletions and replacements. */
- else if (status == svn_wc__db_status_normal
- || status == svn_wc__db_status_deleted
- || replaced
- || (status == svn_wc__db_status_added && !is_add_root))
- {
- /* Revert the prop and text mods (if any). */
- SVN_ERR(revert_admin_things(&reverted, db, local_abspath,
- use_commit_times, pool));
-
- /* Force recursion on replaced directories. */
- if (kind == svn_wc__db_kind_dir && replaced)
- *depth = svn_depth_infinity;
- }
-
- /* If PATH was reverted, tell our client that. */
- if (reverted)
- *did_revert = TRUE;
-
- return SVN_NO_ERROR;
-}
-
/* Verifies if an add (or copy) to LOCAL_ABSPATH can be reverted with depth
* DEPTH, without touching nodes that are filtered by DEPTH.
*
@@ -1393,6 +1330,7 @@ verify_revert_depth(svn_wc__db_t *db,
documentation. */
static svn_error_t *
revert_internal(svn_wc__db_t *db,
+ const char *revert_root,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
@@ -1404,10 +1342,14 @@ revert_internal(svn_wc__db_t *db,
apr_pool_t *pool)
{
svn_node_kind_t disk_kind;
- svn_wc__db_status_t status;
+ svn_wc__db_status_t status, base_status;
svn_wc__db_kind_t db_kind;
svn_boolean_t unversioned;
+ svn_boolean_t have_base;
+ svn_boolean_t replaced;
+ svn_boolean_t reverted = FALSE;
const svn_wc_conflict_description2_t *tree_conflict;
+ const char *op_root_abspath = NULL;
svn_error_t *err;
/* Check cancellation here, so recursive calls get checked early. */
@@ -1420,7 +1362,7 @@ revert_internal(svn_wc__db_t *db,
err = svn_wc__db_read_info(&status, &db_kind,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, &have_base, NULL, NULL,
NULL,
db, local_abspath, pool, pool);
@@ -1439,11 +1381,30 @@ revert_internal(svn_wc__db_t *db,
case svn_wc__db_status_excluded:
unversioned = TRUE;
break;
+ case svn_wc__db_status_incomplete:
+ /* Remove NAME from PATH's entries file
+
+ Not being able to revert incomplete entries breaks working
+ copies flat out, but the usual revert process can't be
+ applied. Most preconditions aren't met. */
+ SVN_ERR(svn_wc__db_temp_op_remove_entry(db, local_abspath, pool));
+ return SVN_NO_ERROR;
+ break;
default:
unversioned = FALSE;
break;
}
+ if (! unversioned && have_base)
+ SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ db, local_abspath, pool, pool));
+
+ replaced = ! unversioned && (status == svn_wc__db_status_added
+ && have_base
+ && base_status != svn_wc__db_status_not_present);
+
SVN_ERR(svn_wc__db_op_read_tree_conflict(&tree_conflict, db, local_abspath,
pool, pool));
if (unversioned && tree_conflict == NULL)
@@ -1483,8 +1444,13 @@ revert_internal(svn_wc__db_t *db,
svn_dirent_local_style(local_abspath, pool));
/* Safeguard 3: can we deal with the node kind of PATH currently in
- the working copy? */
- if ((disk_kind != svn_node_none)
+ the working copy?
+
+ Note: we can reach this point for paths which have tree conflict info
+ set on them. Those are not necessarily nodes we can version,
+ meaning this check doesn't make sense for unversioned nodes. */
+ if (!unversioned
+ && (disk_kind != svn_node_none)
&& (disk_kind != svn_node_file)
&& (disk_kind != svn_node_dir))
return svn_error_createf
@@ -1492,17 +1458,18 @@ revert_internal(svn_wc__db_t *db,
_("Cannot revert '%s': unsupported node kind in working copy"),
svn_dirent_local_style(local_abspath, pool));
+ if (!unversioned && status == svn_wc__db_status_added)
+ SVN_ERR(svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ db, local_abspath, pool, pool));
+
/* Safeguard 4: Make sure we don't revert deeper then asked */
- if (status == svn_wc__db_status_added
+ if (!unversioned
+ && status == svn_wc__db_status_added
&& db_kind == svn_wc__db_kind_dir
&& depth >= svn_depth_empty
&& depth < svn_depth_infinity)
{
- const char *op_root_abspath;
- SVN_ERR(svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- db, local_abspath, pool, pool));
-
/* If this node is an operation root for a copy/add, then reverting
it will change its descendants, if it has any. */
if (strcmp(local_abspath, op_root_abspath) == 0)
@@ -1514,7 +1481,6 @@ revert_internal(svn_wc__db_t *db,
if (svn_wc__internal_changelist_match(db, local_abspath, changelist_hash,
pool))
{
- svn_boolean_t reverted = FALSE;
const svn_wc_conflict_description2_t *conflict;
/* Clear any tree conflict on the path, even if it is not a versioned
@@ -1531,10 +1497,19 @@ revert_internal(svn_wc__db_t *db,
/* Actually revert this entry. If this is a working copy root,
we provide a base_name from the parent path. */
if (!unversioned)
- SVN_ERR(revert_entry(&depth, db, local_abspath, disk_kind,
- use_commit_times,
- cancel_func, cancel_baton,
- &reverted, pool));
+ {
+ /* Revert the prop, text and tree mods (if any). */
+ SVN_ERR(svn_wc__wq_add_revert(&reverted, db, revert_root,
+ local_abspath, use_commit_times,
+ pool));
+ SVN_ERR(svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton, pool));
+
+ /* Force recursion on replaced directories. */
+ if (db_kind == svn_wc__db_kind_dir && replaced)
+ depth = svn_depth_infinity;
+
+ }
/* Notify */
if (notify_func && reverted)
@@ -1544,7 +1519,23 @@ revert_internal(svn_wc__db_t *db,
pool);
}
+
+ if (op_root_abspath && strcmp(local_abspath, op_root_abspath) == 0)
+ /* If this is a copy or add root, disable notifications for the children,
+ because wc-1.0 used to behave like that. */
+ {
+ notify_func = NULL;
+ notify_baton = NULL;
+ }
+
/* Finally, recurse if requested. */
+
+ /* ### This doesn't work properly for added directories. Reverting
+ ### the parent before the children is wrong, it means node rows
+ ### exist for the children after the parent row is removed.
+ ### Either the wq revert of the parent above has to remove the
+ ### children or this recursion has to do children before parents.
+ */
if (!unversioned && db_kind == svn_wc__db_kind_dir && depth > svn_depth_empty)
{
const apr_array_header_t *children;
@@ -1587,7 +1578,7 @@ revert_internal(svn_wc__db_t *db,
continue;
/* Revert the entry. */
- SVN_ERR(revert_internal(db, node_abspath,
+ SVN_ERR(revert_internal(db, revert_root, node_abspath,
depth_under_here, use_commit_times,
changelist_hash, cancel_func, cancel_baton,
notify_func, notify_baton, iterpool));
@@ -1631,7 +1622,8 @@ revert_internal(svn_wc__db_t *db,
const svn_wc_conflict_description2_t *);
if (conflict->kind == svn_wc_conflict_kind_tree)
- SVN_ERR(revert_internal(db, conflict->local_abspath,
+ SVN_ERR(revert_internal(db, revert_root,
+ conflict->local_abspath,
svn_depth_empty,
use_commit_times, changelist_hash,
cancel_func, cancel_baton,
@@ -1644,6 +1636,20 @@ revert_internal(svn_wc__db_t *db,
svn_pool_destroy(iterpool);
}
+ if (reverted /* implies !unversioned; only versioned paths get reverted */
+ && ! replaced
+ && status == svn_wc__db_status_added
+ && db_kind == svn_wc__db_kind_dir)
+ {
+ /* Non-replaced directories have their admin area deleted. wc-1.0 */
+ /* In wc-ng, this call does not really delete the admin area - since
+ there isn't one - but it does destroy the adm_access structure
+ which may be cached inside DB, if the DB is used with old entries
+ functions. */
+ SVN_ERR(svn_wc__adm_destroy(db, local_abspath,
+ cancel_func, cancel_baton, pool));
+ }
+
return SVN_NO_ERROR;
}
@@ -1666,7 +1672,7 @@ svn_wc_revert4(svn_wc_context_t *wc_ctx,
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelists, pool));
return svn_error_return(revert_internal(wc_ctx->db,
- local_abspath, depth,
+ local_abspath, local_abspath, depth,
use_commit_times, changelist_hash,
cancel_func, cancel_baton,
notify_func, notify_baton,