Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 17323)
+++ subversion/include/svn_io.h (working copy)
@@ -677,6 +677,18 @@ svn_error_t *svn_io_remove_file (const c
/** Recursively remove directory @a path. @a path is utf8-encoded. */
svn_error_t *svn_io_remove_dir (const char *path, apr_pool_t *pool);
+/** Read all of the disk entries in directory @a path, a utf8-encoded
+ * path. Set @a *dirents to a hash mapping dirent names (char *) to
+ * dirent names, allocated in @a pool.
+ *
+ * @note The `.' and `..' directories normally returned by
+ * apr_dir_read() are NOT returned in the hash.
+ *
+ * @since New in 1.4.
+ */
+svn_error_t *svn_io_get_dir_filenames (apr_hash_t **dirents,
+ const char *path,
+ apr_pool_t *pool);
/** Read all of the disk entries in directory @a path, a utf8-encoded
* path. Set @a *dirents to a hash mapping dirent names (char *) to
Index: subversion/libsvn_wc/adm_crawler.c
===================================================================
--- subversion/libsvn_wc/adm_crawler.c (revision 17323)
+++ subversion/libsvn_wc/adm_crawler.c (working copy)
@@ -184,7 +184,7 @@ report_revisions (svn_wc_adm_access_t *a
dir_path, subpool);
SVN_ERR (svn_wc_adm_retrieve (&dir_access, adm_access, full_path, subpool));
SVN_ERR (svn_wc_entries_read (&entries, dir_access, TRUE, subpool));
- SVN_ERR (svn_io_get_dirents2 (&dirents, full_path, subpool));
+ SVN_ERR (svn_io_get_dir_filenames (&dirents, full_path, subpool));
/*** Do the real reporting and recursing. ***/
@@ -267,8 +267,6 @@ report_revisions (svn_wc_adm_access_t *a
if (dirent_kind == svn_node_none)
missing = TRUE;
}
- else
- dirent_kind = dirent->kind;
/* From here on out, ignore any entry scheduled for addition */
if (current_entry->schedule == svn_wc_schedule_add)
@@ -277,17 +275,6 @@ report_revisions (svn_wc_adm_access_t *a
/*** Files ***/
if (current_entry->kind == svn_node_file)
{
- /* If the dirent changed kind, report it as missing and
- move on to the next entry. Later on, the update
- editor will return an 'obstructed update' error. :) */
- if ((dirent_kind != svn_node_none)
- && (dirent_kind != svn_node_file)
- && (! report_everything))
- {
- SVN_ERR (reporter->delete_path (report_baton, this_path,
- iterpool));
- continue;
- }
/* If the item is missing from disk, and we're supposed to
restore missing things, and it isn't missing as a result
@@ -367,19 +354,6 @@ report_revisions (svn_wc_adm_access_t *a
iterpool));
continue;
}
-
- /* No excuses here. If the user changed a versioned
- directory into something else, the working copy is hosed.
- It can't receive updates within this dir anymore. Throw
- a real error. */
- if ((dirent_kind != svn_node_none) && (dirent_kind != svn_node_dir))
- {
- return svn_error_createf
- (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
- _("The entry '%s' is no longer a directory; "
- "remove the entry before updating"),
- svn_path_local_style (this_path, iterpool));
- }
/* We need to read the full entry of the directory from its
own "this dir", if available. */
Index: subversion/libsvn_wc/lock.c
===================================================================
--- subversion/libsvn_wc/lock.c (revision 17323)
+++ subversion/libsvn_wc/lock.c (working copy)
@@ -675,10 +675,89 @@ svn_wc_adm_retrieve (svn_wc_adm_access_t
generally makes the calling code simpler as it doesn't need to check
for NULL batons. */
if (! *adm_access)
- return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
- _("Working copy '%s' is missing or not locked"),
- svn_path_local_style (path, pool));
+ {
+ const char *wcpath;
+ const svn_wc_entry_t *subdir_entry;
+ svn_node_kind_t wckind;
+ svn_node_kind_t kind;
+ svn_error_t *err;
+
+ err = svn_wc_entry (&subdir_entry, path, associated, TRUE, pool);
+
+ /* If we can't get an entry here, we are in pretty bad shape,
+ and will have to fall back to using just regular old paths to
+ see what's going on. */
+ if (err)
+ {
+ err = NULL;
+ subdir_entry = NULL;
+ }
+
+ err = svn_io_check_path (path, &kind, pool);
+
+ /* If we can't check the path, we can't make a good error
+ message. */
+ if (err)
+ {
+ svn_error_clear (err);
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Unable to check path existence for %s"),
+ svn_path_local_style (path, pool));
+ }
+
+ if (subdir_entry)
+ {
+ if (subdir_entry->kind == svn_node_dir
+ && kind == svn_node_file)
+ {
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Expected %s to be a directory but found a file"),
+ svn_path_local_style (path, pool));
+ }
+ else if (subdir_entry->kind == svn_node_file
+ && kind == svn_node_dir)
+ {
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Expected %s to be a file but found a directory"),
+ svn_path_local_style (path, pool));
+ }
+ }
+
+ wcpath = svn_wc__adm_path (path, FALSE, pool, NULL);
+ err = svn_io_check_path (wcpath, &wckind, pool);
+
+ /* If we can't check the path, we can't make a good error
+ message. */
+ if (err)
+ {
+ svn_error_clear (err);
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Unable to check path existence for %s"),
+ svn_path_local_style (wcpath, pool));
+ }
+
+ if (kind == svn_node_none)
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Directory '%s' is missing"),
+ svn_path_local_style (path, pool));
+
+ else if (kind == svn_node_dir && wckind == svn_node_none)
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Directory '%s' containing working copy admin area is missing"),
+ svn_path_local_style (wcpath, pool));
+
+ else if (kind == svn_node_dir && wckind == svn_node_dir)
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Unable to lock %s"),
+ svn_path_local_style (path, pool));
+
+ /* If all else fails, return our useless generic error. */
+ return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("Working copy '%s' is missing or not locked"),
+ svn_path_local_style (path, pool));
+
+ }
return SVN_NO_ERROR;
}
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 17323)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -1718,7 +1718,50 @@ svn_io_remove_dir (const char *path, apr
return APR_SUCCESS;
}
+svn_error_t *
+svn_io_get_dir_filenames (apr_hash_t **dirents,
+ const char *path,
+ apr_pool_t *pool)
+{
+ apr_status_t status;
+ apr_dir_t *this_dir;
+ apr_finfo_t this_entry;
+ apr_int32_t flags = APR_FINFO_NAME;
+
+ *dirents = apr_hash_make (pool);
+
+ SVN_ERR (svn_io_dir_open (&this_dir, path, pool));
+
+ for (status = apr_dir_read (&this_entry, flags, this_dir);
+ status == APR_SUCCESS;
+ status = apr_dir_read (&this_entry, flags, this_dir))
+ {
+ if ((this_entry.name[0] == '.')
+ && ((this_entry.name[1] == '\0')
+ || ((this_entry.name[1] == '.')
+ && (this_entry.name[2] == '\0'))))
+ {
+ continue;
+ }
+ else
+ {
+ const char *name;
+ SVN_ERR (svn_path_cstring_to_utf8 (&name, this_entry.name, pool));
+ apr_hash_set (*dirents, name, APR_HASH_KEY_STRING, name);
+ }
+ }
+
+ if (! (APR_STATUS_IS_ENOENT (status)))
+ return svn_error_wrap_apr (status, _("Can't read directory '%s'"),
+ svn_path_local_style (path, pool));
+ status = apr_dir_close (this_dir);
+ if (status)
+ return svn_error_wrap_apr (status, _("Error closing directory '%s'"),
+ svn_path_local_style (path, pool));
+
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_io_get_dirents2 (apr_hash_t **dirents,