You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/11/04 21:48:30 UTC
svn commit: r1031230 [8/21] - in /subversion/branches/py-tests-as-modules:
./ build/ build/ac-macros/ build/win32/ contrib/client-side/ notes/
notes/http-and-webdav/ notes/wc-ng/ subversion/bindings/ctypes-python/csvn/
subversion/bindings/javahl/native...
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_subr/svn_string.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_subr/svn_string.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_subr/svn_string.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_subr/svn_string.c Thu Nov 4 20:48:21 2010
@@ -114,6 +114,10 @@ find_char_backward(const char *str, apr_
/* svn_string functions */
+/* Return a new svn_string_t object, allocated in POOL, initialized with
+ * DATA and SIZE. Do not copy the contents of DATA, just store the pointer.
+ * SIZE is the length in bytes of DATA, excluding the required NUL
+ * terminator. */
static svn_string_t *
create_string(const char *data, apr_size_t size,
apr_pool_t *pool)
@@ -246,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';
@@ -257,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
@@ -364,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)
{
@@ -388,28 +404,60 @@ svn_stringbuf_ensure(svn_stringbuf_t *st
}
+/* WARNING - Optimized code ahead!
+ * This function has been hand-tuned for performance. Please read
+ * the comments below before modifying the code.
+ */
void
svn_stringbuf_appendbyte(svn_stringbuf_t *str, char byte)
{
+ char *dest;
+ apr_size_t old_len = str->len;
+
/* In most cases, there will be pre-allocated memory left
* to just write the new byte at the end of the used section
* and terminate the string properly.
*/
- apr_size_t old_len = str->len;
if (str->blocksize > old_len + 1)
{
- char *dest = str->data;
+ /* The following read does not depend this write, so we
+ * can issue the write first to minimize register pressure:
+ * The value of old_len+1 is no longer needed; on most processors,
+ * dest[old_len+1] will be calculated implicitly as part of
+ * the addressing scheme.
+ */
+ str->len = old_len+1;
+
+ /* Since the compiler cannot be sure that *src->data and *src
+ * don't overlap, we read src->data *once* before writing
+ * to *src->data. Replacing dest with str->data would force
+ * the compiler to read it again after the first byte.
+ */
+ dest = str->data;
+ /* If not already available in a register as per ABI, load
+ * "byte" into the register (e.g. the one freed from old_len+1),
+ * then write it to the string buffer and terminate it properly.
+ *
+ * Including the "byte" fetch, all operations so far could be
+ * issued at once and be scheduled at the CPU's descression.
+ * Most likely, no-one will soon depend on the data that will be
+ * written in this function. So, no stalls there, either.
+ */
dest[old_len] = byte;
dest[old_len+1] = '\0';
-
- str->len = old_len+1;
}
else
{
/* we need to re-allocate the string buffer
* -> let the more generic implementation take care of that part
*/
+
+ /* Depending on the ABI, "byte" is a register value. If we were
+ * to take its address directly, the compiler might decide to
+ * put in on the stack *unconditionally*, even if that would
+ * only be necessary for this block.
+ */
char b = byte;
svn_stringbuf_appendbytes(str, &b, 1);
}
@@ -661,7 +709,7 @@ svn_cstring_strtoui64(apr_uint64_t *n, c
val < 0 || (apr_uint64_t)val < minval || (apr_uint64_t)val > maxval)
return svn_error_return(
svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Number '%s' is out of range '[%lu, %lu]'"),
+ _("Number '%s' is out of range '[%llu, %llu]'"),
str, minval, maxval));
*n = val;
return SVN_NO_ERROR;
@@ -705,7 +753,7 @@ svn_cstring_strtoi64(apr_int64_t *n, con
val < minval || val > maxval)
return svn_error_return(
svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Number '%s' is out of range '[%ld, %ld]'"),
+ _("Number '%s' is out of range '[%lld, %lld]'"),
str, minval, maxval));
*n = val;
return SVN_NO_ERROR;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_subr/utf.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_subr/utf.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_subr/utf.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_subr/utf.c Thu Nov 4 20:48:21 2010
@@ -155,7 +155,7 @@ get_xlate_key(const char *topage,
topage = "APR_DEFAULT_CHARSET";
return apr_pstrcat(pool, "svn-utf-", frompage, "to", topage,
- "-xlate-handle", NULL);
+ "-xlate-handle", (char *)NULL);
}
/* Set *RET to a handle node for converting from FROMPAGE to TOPAGE,
@@ -588,7 +588,8 @@ invalid_utf8(const char *data, apr_size_
for (i = 0; i < valid; ++i)
valid_txt = apr_pstrcat(pool, valid_txt,
apr_psprintf(pool, " %02x",
- (unsigned char)last[i-valid]), NULL);
+ (unsigned char)last[i-valid]),
+ (char *)NULL);
/* 4 invalid octets will guarantee that the faulty octet is displayed */
invalid = data + len - last;
@@ -597,7 +598,8 @@ invalid_utf8(const char *data, apr_size_
for (i = 0; i < invalid; ++i)
invalid_txt = apr_pstrcat(pool, invalid_txt,
apr_psprintf(pool, " %02x",
- (unsigned char)last[i]), NULL);
+ (unsigned char)last[i]),
+ (char *)NULL);
return svn_error_createf(APR_EINVAL, NULL,
_("Valid UTF-8 data\n(hex:%s)\n"
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_crawler.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_crawler.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_crawler.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_crawler.c Thu Nov 4 20:48:21 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,
@@ -748,52 +770,21 @@ svn_wc_crawl_revisions5(svn_wc_context_t
db, local_abspath, scratch_pool,
scratch_pool);
- {
- svn_boolean_t has_base = TRUE;
+ 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);
+ SVN_ERR(svn_wc__db_read_kind(&target_kind, db, local_abspath, TRUE,
+ scratch_pool));
- svn_error_clear(err);
- has_base = FALSE;
- SVN_ERR(svn_wc__db_read_kind(&target_kind, db, local_abspath, TRUE,
- scratch_pool));
-
- if (target_kind == svn_wc__db_kind_file
- || target_kind == svn_wc__db_kind_symlink)
- status = svn_wc__db_status_absent; /* Crawl via parent dir */
- else
- status = svn_wc__db_status_not_present; /* As checkout */
- }
-
- /* ### Check the parentstub if we don't find a BASE. But don't
- do this if we already have the info we want or we break
- some copy scenarios. */
- if (!has_base && target_kind == svn_wc__db_kind_dir)
- {
- svn_boolean_t not_present;
- svn_revnum_t rev = SVN_INVALID_REVNUM;
- err = svn_wc__db_temp_is_dir_deleted(¬_present, &rev,
- db, local_abspath, scratch_pool);
-
- if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND
- || err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY))
- {
- svn_error_clear(err);
- not_present = FALSE;
- }
- else
- SVN_ERR(err);
-
- if (not_present)
- status = svn_wc__db_status_not_present;
-
- if (!SVN_IS_VALID_REVNUM(target_rev))
- target_rev = rev;
- }
- }
+ if (target_kind == svn_wc__db_kind_file
+ || target_kind == svn_wc__db_kind_symlink)
+ status = svn_wc__db_status_absent; /* Crawl via parent dir */
+ else
+ status = svn_wc__db_status_not_present; /* As checkout */
+ }
if ((status == svn_wc__db_status_not_present)
|| (target_kind == svn_wc__db_kind_dir
@@ -956,15 +947,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/py-tests-as-modules/subversion/libsvn_wc/adm_files.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_files.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_files.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_files.c Thu Nov 4 20:48:21 2010
@@ -119,7 +119,7 @@ simple_extend(const char *adm_path, /*
if (subdir)
child = svn_dirent_join(subdir, child, result_pool);
if (extension)
- child = apr_pstrcat(result_pool, child, extension, NULL);
+ child = apr_pstrcat(result_pool, child, extension, (char *)NULL);
if (use_tmp)
return svn_dirent_join_many(result_pool,
@@ -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/py-tests-as-modules/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_ops.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/adm_ops.c Thu Nov 4 20:48:21 2010
@@ -735,28 +735,129 @@ 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)
+ /* 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));
+
+ /* 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 +865,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 +874,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 +886,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 +1074,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 +1086,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 +1116,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,194 +1259,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_absent_node(
- db, local_abspath,
- repos_relpath, repos_root_url, repos_uuid,
- base_revision,
- base_kind,
- svn_wc__db_status_not_present,
- 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.
*
@@ -1394,6 +1332,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,
@@ -1405,10 +1344,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. */
@@ -1421,7 +1364,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);
@@ -1440,11 +1383,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)
@@ -1484,8 +1446,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
@@ -1493,17 +1460,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)
@@ -1515,7 +1483,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
@@ -1532,10 +1499,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)
@@ -1545,7 +1521,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;
@@ -1588,7 +1580,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));
@@ -1632,7 +1624,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,
@@ -1645,6 +1638,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;
}
@@ -1667,7 +1674,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,
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/conflicts.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/conflicts.c Thu Nov 4 20:48:21 2010
@@ -50,152 +50,6 @@
#include "svn_private_config.h"
-struct svn_wc_conflict_t
-{
- /* ### kind + property name are the primary keys of a conflict */
- /* The kind of conflict recorded */
- svn_wc_conflict_kind_t kind;
-
- /* When describing a property conflict the property name
- or "" when no property name is available. (Upgrade from old WC or
- raised via compatibility apis). */
- const char *property_name;
-
- /* ### TODO: Add more fields */
-};
-
-/* */
-static svn_error_t *
-conflict_alloc(svn_wc_conflict_t **conflict, apr_pool_t *result_pool)
-{
- svn_wc_conflict_t *c = apr_pcalloc(result_pool, sizeof(*c));
-
- *conflict = c;
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc_conflict_dup(svn_wc_conflict_t **duplicate,
- const svn_wc_conflict_t *base,
- apr_pool_t *result_pool)
-{
- svn_wc_conflict_t *c;
-
- SVN_ERR(conflict_alloc(&c, result_pool));
-
- c->kind = base->kind;
- c->property_name = base->property_name
- ? apr_pstrdup(result_pool, base->property_name)
- : NULL;
-
- *duplicate = c;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc_create_property_conflict(svn_wc_conflict_t **conflict,
- const char *property_name,
- const svn_wc_conflict_version_t *older_version,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- const svn_string_t *older_value,
- const svn_string_t *left_value,
- const svn_string_t *right_value,
- const char *marker_abspath,
- svn_wc_operation_t operation,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-svn_error_t *
-svn_wc_create_text_conflict(svn_wc_conflict_t **conflict,
- const svn_wc_conflict_version_t *older_version,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- const char *older_abspath,
- const char *left_abspath,
- const char *right_abspath,
- svn_wc_operation_t operation,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-svn_error_t *
-svn_wc_create_tree_conflict(svn_wc_conflict_t **conflict,
- const svn_wc_conflict_version_t *older_version,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- svn_wc_conflict_action_t action,
- svn_wc_conflict_reason_t reason,
- svn_wc_operation_t operation,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-svn_error_t *
-svn_wc_get_conflict_info(svn_wc_conflict_kind_t *kind,
- const char **property_name,
- svn_wc_conflict_action_t *action,
- svn_wc_conflict_reason_t *reason,
- svn_wc_operation_t *operation,
- svn_boolean_t *conflict_resolved,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- svn_wc_conflict_t *conflict,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-
-svn_error_t *
-svn_wc_get_conflict_marker_files(const char **older_abspath,
- const char **left_abspath,
- const char **right_abspath,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- svn_wc_conflict_t *conflict,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-svn_error_t *
-svn_wc_get_conflict_sources(const svn_wc_conflict_version_t **older_version,
- const svn_wc_conflict_version_t **left_version,
- const svn_wc_conflict_version_t **right_version,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- svn_wc_conflict_t *conflict,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-svn_error_t *
-svn_wc_get_property_conflict_data(const svn_string_t **older_value,
- const svn_string_t **left_value,
- const svn_string_t **right_value,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- svn_wc_conflict_t *conflict,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_MALFUNCTION(); /* ### Not implemented yet */
-}
-
-
svn_skel_t *
svn_wc__conflict_skel_new(apr_pool_t *result_pool)
{
@@ -312,6 +166,8 @@ attempt_deletion(const char *parent_dir,
### leave, for example, one of the conflict artifact files deleted but
### the entry still referring to it and trying to use it for the next
### attempt at resolving.
+
+ ### Does this still apply in the world of WC-NG? -hkw
*/
static svn_error_t *
resolve_conflict_on_node(svn_wc__db_t *db,
@@ -334,11 +190,7 @@ resolve_conflict_on_node(svn_wc__db_t *d
*did_resolve = FALSE;
- SVN_ERR(svn_wc__db_read_info(NULL, &kind, 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, pool, pool));
+ SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, TRUE, pool));
SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
pool, pool));
@@ -366,6 +218,7 @@ resolve_conflict_on_node(svn_wc__db_t *d
if (resolve_text)
{
+ svn_stream_t *tmp_stream = NULL;
const char *auto_resolve_src;
/* Handle automatic conflict resolution before the temporary files are
@@ -390,7 +243,6 @@ resolve_conflict_on_node(svn_wc__db_t *d
if (conflict_old && conflict_working && conflict_new)
{
const char *temp_dir;
- svn_stream_t *tmp_stream;
svn_diff_t *diff;
svn_diff_conflict_display_style_t style =
conflict_choice == svn_wc_conflict_choose_theirs_conflict
@@ -402,7 +254,8 @@ resolve_conflict_on_node(svn_wc__db_t *d
pool, pool));
SVN_ERR(svn_stream_open_unique(&tmp_stream,
&auto_resolve_src,
- temp_dir, svn_io_file_del_none,
+ temp_dir,
+ svn_io_file_del_on_close,
pool, pool));
/* ### If any of these paths isn't absolute, treat it
@@ -436,7 +289,6 @@ resolve_conflict_on_node(svn_wc__db_t *d
NULL, NULL, NULL, NULL,
style,
pool));
- SVN_ERR(svn_stream_close(tmp_stream));
}
else
auto_resolve_src = NULL;
@@ -451,6 +303,9 @@ resolve_conflict_on_node(svn_wc__db_t *d
SVN_ERR(svn_io_copy_file(
svn_dirent_join(conflict_dir_abspath, auto_resolve_src, pool),
local_abspath, TRUE, pool));
+
+ if (tmp_stream)
+ SVN_ERR(svn_stream_close(tmp_stream));
}
/* Records whether we found any of the conflict files. */