Teach some WC and client 'add' functions to take the properties as a
parameter so that the whole addition including any properties can be done
all at once.

### TODO:
  svn_wc_canonicalize_svn_prop() is not really WC-specific; the only thing
  tying it to libsvn_wc is a dependency on the svn:externals syntax.  It
  should therefore be called from libsvn_client layer, as it already is from
  propset_on_url() and the dry-run case in install_patched_prop_targets().
  It should not be called within svn_wc_prop_set4(), so we should deprecate
  and rev that.

  The 'prop_getter' callback of svn_wc_canonicalize_svn_prop() is
  ill-defined: one caller passes null, and it's not clear what MIME type
  it's supposed to return.

### This is currently a half-way implementation with #ifdef.

### All tests passed last time I tried; wasn't quite this version of code.

* subversion/libsvn_client/add.c
  (add_file): Simplify by passing the props to svn_wc_add_from_disk().
  (add_dir_recursive, add): Pass NULL for props.

* subversion/libsvn_client/patch.c
  (create_missing_parents,
   install_patched_target,
   install_patched_prop_targets): Pass NULL for props.

* subversion/include/svn_wc.h
  (svn_wc_add_from_disk2): New revision of svn_wc_add_from_disk(), taking a
    'props' parameter.
  (svn_wc_add_from_disk): Deprecate.

* subversion/include/private/svn_wc_private.h
  (svn_wc__set_props): New function.

* subversion/libsvn_wc/adm_ops.c
  (add_from_disk): Take a 'props' parameter and pass it on.
  (svn_wc_add4): Pass NULL for props.
  (svn_wc_add_from_disk2): Rename from 'svn_wc_add_from_disk'. Handle the
    'props' parameter.
### half-way

* subversion/libsvn_wc/deprecated.c
  (svn_wc_add_from_disk): New function: a wrapper around
    svn_wc_add_from_disk2().

* subversion/libsvn_wc/props.h
  (svn_wc__internal_set_props): New function.

* subversion/libsvn_wc/props.c
  (check_regular_prop_valid): New function, factored out...
### currently empty
  (do_propset): ... from here.
  (ensure_prop_is_regular_kind): New function, factored out...
  (svn_wc_prop_set4): ... from here.

* subversion/libsvn_wc/wc_db.h,
  subversion/libsvn_wc/wc_db.c
  (svn_wc__db_op_add_directory,
   svn_wc__db_op_add_file,
   svn_wc__db_op_add_symlink): Take a 'props' parameter.

* subversion/tests/libsvn_wc/conflict-data-test.c
  (test_read_write_tree_conflicts): Pass NULL for props.

* subversion/tests/libsvn_wc/utils.c
  (sbox_wc_add): Pass NULL for props.
--This line, and those below, will be ignored--

* subversion/include/private/svn_wc_private.h
  (svn_wc__get_cached_iprop_children): 

* subversion/include/svn_wc.h
  (svn_wc_delete): 

* subversion/libsvn_client/add.c
  (add_file): 
  (add_dir_recursive): 
  (add): 

* subversion/libsvn_client/patch.c
  (create_missing_parents): 
  (install_patched_target): 
  (install_patched_prop_targets): 

* subversion/libsvn_wc/adm_ops.c
  (svn_wc_delete4): 
  (add_from_disk): 
  (svn_wc_add4): 
  (svn_wc_add_from_disk): 

* subversion/libsvn_wc/deprecated.c

* subversion/libsvn_wc/props.c
  (get_file_for_validation): 
  (validate_eol_prop_against_file): 
  (propset_walk_cb): 
  (svn_wc_prop_set4): 

* subversion/libsvn_wc/props.h
  (svn_wc__internal_propget): 

* subversion/libsvn_wc/wc_db.c
  (svn_wc__db_op_add_directory): 
  (svn_wc__db_op_add_file): 
  (svn_wc__db_op_add_symlink): 

* subversion/libsvn_wc/wc_db.h
  (svn_wc__db_op_add_directory): 
  (svn_wc__db_op_add_file): 
  (svn_wc__db_op_add_symlink): 

* subversion/tests/libsvn_wc/conflict-data-test.c
  (test_read_write_tree_conflicts): 

* subversion/tests/libsvn_wc/utils.c
  (sbox_wc_add): 

--This line, and those below, will be ignored--

Index: subversion/include/private/svn_wc_private.h
===================================================================
--- subversion/include/private/svn_wc_private.h	(revision 1423220)
+++ subversion/include/private/svn_wc_private.h	(working copy)
@@ -906,6 +906,20 @@ svn_wc__get_cached_iprop_children(apr_ha
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool);
 
+/* Set the actual properties of the node LOCAL_ABSPATH to PROPS.
+ *
+ * Validate and canonicalize the properties like svn_wc_prop_set4() does;
+ * see that function for details of the SKIP_CHECKS option.
+ *
+ * Change the on-disk executable and read-only bits as required.
+ */
+svn_error_t *
+svn_wc__set_props(svn_wc_context_t *wc_ctx,
+                  const char *local_abspath,
+                  const apr_hash_t *props,
+                  svn_boolean_t skip_checks,
+                  apr_pool_t *scratch_pool);
+
 
 /**
  * For use by entries.c and entries-dump.c to read old-format working copies.
Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h	(revision 1423220)
+++ subversion/include/svn_wc.h	(working copy)
@@ -4528,7 +4528,16 @@ svn_wc_delete(const char *path,
 
 /**
  * Schedule the single node that exists on disk at @a local_abspath for
- * addition to the working copy.  The added node will have no properties.
+ * addition to the working copy.  The added node will have the properties
+ * provided in @a props, or none if that is NULL.
+ *
+ * Check and canonicalize the properties in the same way as
+ * svn_wc_prop_set4().  Return an error and don't add the node if the
+ * properties are not valid on this node.  Unlike svn_wc_prop_set4()
+ * there is no option to skip some of the checks and canonicalizations.
+ *
+ * ### The error code on validity check failure should be specified, and
+ *     preferably should be a single code.
  *
  * The versioned state of the parent path must be a modifiable directory,
  * and the versioned state of @a local_abspath must be either nonexistent or
@@ -4537,14 +4546,28 @@ svn_wc_delete(const char *path,
  * If @a local_abspath does not exist as file, directory or symlink, return
  * #SVN_ERR_WC_PATH_NOT_FOUND.
  *
- * This is a replacement for svn_wc_add4() case 2a.
+ * ### TODO: Split into add_dir, add_file, add_symlink?
  *
- * ### TODO: Allow the caller to provide the node's properties?
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_wc_add_from_disk2(svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      const apr_hash_t *props,
+                      svn_wc_notify_func2_t notify_func,
+                      void *notify_baton,
+                      apr_pool_t *scratch_pool);
+
+
+/**
+ * Similar to svn_wc_add4(), but gives the new node an empty set of properties.
  *
- * ### TODO: Split into add_dir, add_file, add_symlink?
+ * This is a replacement for svn_wc_add4() case 2a.
  *
  * @since New in 1.7.
+ * @deprecated Provided for backward compatibility with the 1.7 API.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_wc_add_from_disk(svn_wc_context_t *wc_ctx,
                      const char *local_abspath,
Index: subversion/libsvn_client/add.c
===================================================================
--- subversion/libsvn_client/add.c	(revision 1423220)
+++ subversion/libsvn_client/add.c	(working copy)
@@ -275,7 +275,6 @@ add_file(const char *local_abspath,
          apr_pool_t *pool)
 {
   apr_hash_t *properties;
-  apr_hash_index_t *hi;
   const char *mimetype;
   svn_node_kind_t kind;
   svn_boolean_t is_special;
@@ -283,10 +282,7 @@ add_file(const char *local_abspath,
   /* Check to see if this is a special file. */
   SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &is_special, pool));
 
-  /* Add the file */
-  SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
-                               NULL, NULL, pool));
-
+  /* Determine the properties that the file should have */
   if (is_special)
     {
       mimetype = NULL;
@@ -320,37 +316,9 @@ add_file(const char *local_abspath,
                                                pool));
     }
 
-  /* loop through the hashtable and add the properties */
-  for (hi = apr_hash_first(pool, properties);
-       hi != NULL; hi = apr_hash_next(hi))
-    {
-      const char *pname = svn__apr_hash_index_key(hi);
-      const svn_string_t *pval = svn__apr_hash_index_val(hi);
-      svn_error_t *err;
-
-      /* It's probably best to pass 0 for force, so that if
-         the autoprops say to set some weird combination,
-         we just error and let the user sort it out. */
-      err = svn_wc_prop_set4(ctx->wc_ctx, local_abspath, pname, pval,
-                             svn_depth_empty, FALSE, NULL,
-                             NULL, NULL /* cancellation */,
-                             NULL, NULL /* notification */,
-                             pool);
-      if (err)
-        {
-          /* Don't leave the job half-done. If we fail to set a property,
-           * (try to) un-add the file. */
-          return svn_error_compose_create(
-                   err,
-                   svn_wc_revert4(ctx->wc_ctx,
-                                  local_abspath,
-                                  svn_depth_empty,
-                                  FALSE /* use_commit_times */,
-                                  NULL /* changelists */,
-                                  NULL, NULL, NULL, NULL,
-                                  pool));
-        }
-    }
+  /* Add the file */
+  SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, local_abspath, properties,
+                                NULL, NULL, pool));
 
   /* Report the addition to the caller. */
   if (ctx->notify_func2 != NULL)
@@ -425,9 +393,9 @@ add_dir_recursive(const char *dir_abspat
                                         iterpool));
 
   /* Add this directory to revision control. */
-  err = svn_wc_add_from_disk(ctx->wc_ctx, dir_abspath,
-                             ctx->notify_func2, ctx->notify_baton2,
-                             iterpool);
+  err = svn_wc_add_from_disk2(ctx->wc_ctx, dir_abspath, NULL /*props*/,
+                              ctx->notify_func2, ctx->notify_baton2,
+                              iterpool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
@@ -1009,9 +977,10 @@ add(const char *local_abspath,
                                      parent_abspath, local_abspath);
 
           SVN_ERR(svn_io_make_dir_recursively(parent_abspath, scratch_pool));
-          SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, parent_abspath,
-                                       ctx->notify_func2, ctx->notify_baton2,
-                                       scratch_pool));
+          SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, parent_abspath,
+                                        NULL /*props*/,
+                                        ctx->notify_func2, ctx->notify_baton2,
+                                        scratch_pool));
         }
       svn_pool_destroy(iterpool);
     }
Index: subversion/libsvn_client/patch.c
===================================================================
--- subversion/libsvn_client/patch.c	(revision 1423220)
+++ subversion/libsvn_client/patch.c	(working copy)
@@ -2288,9 +2288,10 @@ create_missing_parents(patch_target_t *t
               if (ctx->cancel_func)
                 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
-              SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
-                                           ctx->notify_func2, ctx->notify_baton2,
-                                           iterpool));
+              SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, local_abspath,
+                                            NULL /*props*/,
+                                            ctx->notify_func2, ctx->notify_baton2,
+                                            iterpool));
             }
         }
     }
@@ -2402,8 +2403,9 @@ install_patched_target(patch_target_t *t
                * Suppress notification, we'll do that later (and also
                * during dry-run). Don't allow cancellation because
                * we'd rather notify about what we did before aborting. */
-              SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
-                                           NULL, NULL, pool));
+              SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, target->local_abspath,
+                                            NULL /*props*/,
+                                            NULL, NULL, pool));
             }
 
           /* Restore the target's executable bit if necessary. */
@@ -2494,10 +2496,11 @@ install_patched_prop_targets(patch_targe
             {
               SVN_ERR(svn_io_file_create(target->local_abspath, "",
                                          scratch_pool));
-              SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
-                                           /* suppress notification */
-                                           NULL, NULL,
-                                           iterpool));
+              SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, target->local_abspath,
+                                            NULL /*props*/,
+                                            /* suppress notification */
+                                            NULL, NULL,
+                                            iterpool));
             }
           target->added = TRUE;
         }
Index: subversion/libsvn_wc/adm_ops.c
===================================================================
--- subversion/libsvn_wc/adm_ops.c	(revision 1423220)
+++ subversion/libsvn_wc/adm_ops.c	(working copy)
@@ -63,6 +63,18 @@
 #include "private/svn_subr_private.h"
 
 
+static svn_error_t *
+revert_internal(svn_wc__db_t *db,
+                const char *local_abspath,
+                svn_depth_t depth,
+                svn_boolean_t use_commit_times,
+                svn_cancel_func_t cancel_func,
+                void *cancel_baton,
+                svn_wc_notify_func2_t notify_func,
+                void *notify_baton,
+                apr_pool_t *scratch_pool);
+
+
 struct svn_wc_committed_queue_t
 {
   /* The pool in which ->queue is allocated. */
@@ -898,23 +910,64 @@ svn_wc_delete4(svn_wc_context_t *wc_ctx,
 
 
 /* Schedule the single node at LOCAL_ABSPATH, of kind KIND, for addition in
- * its parent directory in the WC.  It will have no properties. */
+ * its parent directory in the WC.  It will have the properties
+ * provided in PROPS, or none if that is NULL. */
 static svn_error_t *
 add_from_disk(svn_wc__db_t *db,
               const char *local_abspath,
+              const apr_hash_t *props,
               svn_node_kind_t kind,
               apr_pool_t *scratch_pool)
 {
+#if 0  /* ideal */
+  /* ### Canonicalize and validate props */
+
+  /* Add the node with props */
   if (kind == svn_node_file)
     {
-      SVN_ERR(svn_wc__db_op_add_file(db, local_abspath, NULL, scratch_pool));
+      SVN_ERR(svn_wc__db_op_add_file(db, local_abspath, props,
+                                     NULL, scratch_pool));
     }
   else
     {
-      SVN_ERR(svn_wc__db_op_add_directory(db, local_abspath, NULL,
-                                          scratch_pool));
+      SVN_ERR(svn_wc__db_op_add_directory(db, local_abspath, props,
+                                          NULL, scratch_pool));
+    }
+#else  /* half-way house */
+  /* Add the node without props */
+  if (kind == svn_node_file)
+    {
+      SVN_ERR(svn_wc__db_op_add_file(db, local_abspath, NULL /*props*/,
+                                     NULL, scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(svn_wc__db_op_add_directory(db, local_abspath, NULL /*props*/,
+                                          NULL, scratch_pool));
     }
 
+  /* Set the props, or revert if we can't */
+  if (props)
+    {
+      svn_error_t *err;
+
+      err = svn_wc__internal_set_props(db, local_abspath, props,
+                                       FALSE /* skip_checks */, scratch_pool);
+      if (err)
+        {
+          /* Don't leave the job half-done. If we fail to set a property,
+           * (try to) un-add the file. */
+          return svn_error_compose_create(
+                   err,
+                   revert_internal(db, local_abspath,
+                                   svn_depth_empty, FALSE /*use_commit_times*/,
+                                   NULL, NULL,  /* cancellation */
+                                   NULL, NULL,  /* notification */
+                                   scratch_pool));
+        }
+    }
+#endif
+
   return SVN_NO_ERROR;
 }
 
@@ -1273,7 +1326,7 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
 
   if (!copyfrom_url)  /* Case 2a: It's a simple add */
     {
-      SVN_ERR(add_from_disk(db, local_abspath, kind,
+      SVN_ERR(add_from_disk(db, local_abspath, NULL, kind,
                             scratch_pool));
       if (kind == svn_node_dir && !db_row_exists)
         {
@@ -1346,11 +1399,12 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
 
 
 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_wc_add_from_disk2(svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      const apr_hash_t *props,
+                      svn_wc_notify_func2_t notify_func,
+                      void *notify_baton,
+                      apr_pool_t *scratch_pool)
 {
   svn_node_kind_t kind;
 
@@ -1358,9 +1412,36 @@ svn_wc_add_from_disk(svn_wc_context_t *w
                              NULL, SVN_INVALID_REVNUM, scratch_pool));
   SVN_ERR(check_can_add_to_parent(NULL, NULL, wc_ctx->db, local_abspath,
                                   scratch_pool, scratch_pool));
-  SVN_ERR(add_from_disk(wc_ctx->db, local_abspath, kind,
+#if 0  /* the ideal */
+  SVN_ERR(add_from_disk(wc_ctx->db, local_abspath, props, kind,
+                        scratch_pool));
+#else  /* half-way house */
+  SVN_ERR(add_from_disk(wc_ctx->db, local_abspath, NULL /*props*/, kind,
                         scratch_pool));
 
+  if (props)
+    {
+      svn_error_t *err;
+
+      err = svn_wc__set_props(wc_ctx, local_abspath, props,
+                              FALSE /* skip_checks */, scratch_pool);
+      if (err)
+        {
+          /* Don't leave the job half-done. If we fail to set a property,
+           * (try to) un-add the file. */
+          return svn_error_compose_create(
+                   err,
+                   svn_wc_revert4(wc_ctx,
+                                  local_abspath,
+                                  svn_depth_empty,
+                                  FALSE /* use_commit_times */,
+                                  NULL /* changelists */,
+                                  NULL, NULL, NULL, NULL,
+                                  scratch_pool));
+        }
+    }
+#endif
+
   /* Report the addition to the caller. */
   if (notify_func != NULL)
     {
Index: subversion/libsvn_wc/deprecated.c
===================================================================
--- subversion/libsvn_wc/deprecated.c	(revision 1423220)
+++ subversion/libsvn_wc/deprecated.c	(working copy)
@@ -903,6 +903,18 @@ svn_wc_delete(const char *path,
 }
 
 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_ERR(svn_wc_add_from_disk2(wc_ctx, local_abspath, NULL,
+                                 notify_func, notify_baton, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_wc_add3(const char *path,
             svn_wc_adm_access_t *parent_access,
             svn_depth_t depth,
Index: subversion/libsvn_wc/props.c
===================================================================
--- subversion/libsvn_wc/props.c	(revision 1423220)
+++ subversion/libsvn_wc/props.c	(working copy)
@@ -1608,7 +1608,15 @@ get_file_for_validation(const svn_string
 }
 
 
-/* */
+/* Validate that a file has a 'non-binary' MIME type and contains
+ * self-consistent line endings.  If not, then return an error.
+ *
+ * Call GETTER (which must not be NULL) with GETTER_BATON to get the
+ * file's MIME type and/or content.  If the MIME type is deemed 'binary'
+ * then return an error and do not request the file content.
+ *
+ * Use PATH (a local path or a URL) only for error messages.
+ */
 static svn_error_t *
 validate_eol_prop_against_file(const char *path,
                                svn_wc_canonicalize_svn_prop_get_file_t getter,
@@ -1652,6 +1660,7 @@ validate_eol_prop_against_file(const cha
   return svn_error_trace(err);
 }
 
+/* */
 static svn_error_t *
 do_propset(svn_wc__db_t *db,
            const char *local_abspath,
@@ -1850,6 +1859,27 @@ propset_walk_cb(const char *local_abspat
   return svn_error_trace(err);
 }
 
+/* Check prop validity. Return an error if not valid.
+ * ### Also do canonicalizations? */
+static svn_error_t *
+ensure_prop_is_regular_kind(const char *name)
+{
+  enum svn_prop_kind prop_kind = svn_property_kind2(name);
+
+  /* we don't do entry properties here */
+  if (prop_kind == svn_prop_entry_kind)
+    return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
+                             _("Property '%s' is an entry property"), name);
+
+  /* Check to see if we're setting the dav cache. */
+  if (prop_kind == svn_prop_wc_kind)
+    return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
+                             _("Property '%s' is a WC property, not "
+                               "a regular property"), name);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc_prop_set4(svn_wc_context_t *wc_ctx,
                  const char *local_abspath,
@@ -1868,11 +1898,6 @@ svn_wc_prop_set4(svn_wc_context_t *wc_ct
   svn_kind_t kind;
   svn_wc__db_t *db = wc_ctx->db;
 
-  /* we don't do entry properties here */
-  if (prop_kind == svn_prop_entry_kind)
-    return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
-                             _("Property '%s' is an entry property"), name);
-
   /* Check to see if we're setting the dav cache. */
   if (prop_kind == svn_prop_wc_kind)
     {
@@ -1881,6 +1906,8 @@ svn_wc_prop_set4(svn_wc_context_t *wc_ct
                                         name, value, scratch_pool));
     }
 
+  SVN_ERR(ensure_prop_is_regular_kind(name));
+
   SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, FALSE, FALSE,
                                scratch_pool));
 
@@ -1958,6 +1985,191 @@ svn_wc_prop_set4(svn_wc_context_t *wc_ct
   return SVN_NO_ERROR;
 }
 
+/* Baton for get_file_for_set_props(). */
+typedef struct set_props_baton_t
+{
+  const char *local_abspath;
+  const char *mime_type;
+} set_props_baton_t;
+
+/* Implements svn_wc_canonicalize_svn_prop_get_file_t. */
+static svn_error_t *
+get_file_for_set_props(const svn_string_t **mime_type,
+                       svn_stream_t *stream,
+                       void *baton,
+                       apr_pool_t *pool)
+{
+  struct set_props_baton_t *gb = baton;
+
+  if (mime_type)
+    *mime_type = svn_string_create(gb->mime_type, pool);
+
+  if (stream)
+    {
+      svn_stream_t *read_stream;
+
+      /* Open GB->LOCAL_ABSPATH. */
+      SVN_ERR(svn_stream_open_readonly(&read_stream, gb->local_abspath,
+                                       pool, pool));
+
+      /* Copy from the file into the translating stream. */
+      SVN_ERR(svn_stream_copy3(read_stream, svn_stream_disown(stream, pool),
+                               NULL, NULL, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Check and canonicalize the PROPS.  Set *GOOD_PROPS.
+ * ### ...
+ */
+static svn_error_t *
+canonicalize_props(apr_hash_t **good_props,
+                   const char *local_abspath,
+                   svn_kind_t kind,
+                   const apr_hash_t *props,
+                   svn_boolean_t skip_checks,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  struct set_props_baton_t gb;
+  apr_hash_index_t *hi;
+
+  *good_props = apr_hash_make(result_pool);
+
+  /* Context for canonicalization.
+   * ### Should first canonicalize mime-type before providing it here. */
+  gb.local_abspath = local_abspath;
+  gb.mime_type = svn_prop_get_value((apr_hash_t *)props, SVN_PROP_MIME_TYPE);
+
+  for (hi = apr_hash_first(scratch_pool, (apr_hash_t *)props); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      const svn_string_t *value = svn__apr_hash_index_val(hi);
+
+      SVN_ERR(ensure_prop_is_regular_kind(name));
+
+      SVN_ERR(svn_wc_canonicalize_svn_prop(&value, name, value,
+                                           local_abspath, kind,
+                                           skip_checks,
+                                           get_file_for_set_props, &gb,
+                                           scratch_pool));
+      apr_hash_set(*good_props, name, APR_HASH_KEY_STRING, value);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__internal_set_props(svn_wc__db_t *db,
+                           const char *local_abspath,
+                           const apr_hash_t *props,
+                           svn_boolean_t skip_checks,
+                           apr_pool_t *scratch_pool)
+{
+  svn_kind_t kind;
+  apr_hash_t *good_props;
+  apr_hash_index_t *hi;
+
+  SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, FALSE, FALSE,
+                               scratch_pool));
+
+  /* We have to do this little DIR_ABSPATH dance for backwards compat.
+     But from 1.7 onwards, all locks are of infinite depth, and from 1.6
+     backward we never call this API with depth > empty, so we only need
+     to do the write check once per call, here (and not for every node in
+     the node walker).
+
+     ### Note that we could check for a write lock on local_abspath first
+     ### if we would want to. And then justy check for kind if that fails.
+     ### ... but we need kind for the "svn:" property checks anyway */
+  {
+    const char *dir_abspath;
+
+    if (kind == svn_kind_dir)
+      dir_abspath = local_abspath;
+    else
+      dir_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+
+    /* Verify that we're holding this directory's write lock.  */
+    SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
+  }
+
+  /* Check and canonicalize the new props */
+  SVN_ERR(canonicalize_props(&good_props,
+                             local_abspath, kind, props, skip_checks,
+                             scratch_pool, scratch_pool));
+
+#if 1
+  /* ### Crummy solution: delete current props, then set new props one
+   *     at a time. */
+
+  /* ### TODO: delete current props */
+
+  /* Add new props */
+  for (hi = apr_hash_first(scratch_pool, good_props); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      const svn_string_t *value = svn__apr_hash_index_val(hi);
+      svn_error_t *err;
+
+      err = do_propset(db, local_abspath,
+                         kind == svn_kind_dir
+                            ? svn_node_dir
+                            : svn_node_file,
+                         name, value, skip_checks,
+                         NULL, NULL, scratch_pool);
+
+      if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+        {
+          err = svn_error_createf(SVN_ERR_WC_INVALID_SCHEDULE, err,
+                                  _("Can't set properties on '%s':"
+                                    " invalid status for updating properties."),
+                                  svn_dirent_local_style(local_abspath,
+                                                         scratch_pool));
+        }
+
+      SVN_ERR(err);
+    }
+
+#else
+  /* ### Proper solution:
+         set all the props at once and add WQ items to modify executable
+         and/or read-only attributes. */
+  {
+  svn_skel_t *work_item = NULL;
+  svn_boolean_t clear_recorded_info = FALSE;
+
+  /* ### Figure out CLEAR_RECORDED_INFO and WORK_ITEMS */
+
+  /* Drop the props and work items into the db. */
+  SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, good_props,
+                                  clear_recorded_info, NULL /*conflict*/,
+                                  work_item, scratch_pool));
+
+  /* Run our workqueue item for sync'ing flags with props. */
+  if (work_item)
+    SVN_ERR(svn_wc__wq_run(db, local_abspath, NULL, NULL, scratch_pool));
+  }
+#endif
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__set_props(svn_wc_context_t *wc_ctx,
+                  const char *local_abspath,
+                  const apr_hash_t *props,
+                  svn_boolean_t skip_checks,
+                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_wc__internal_set_props(wc_ctx->db, local_abspath,
+                                     props, skip_checks, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 
 svn_error_t *
 svn_wc_canonicalize_svn_prop(const svn_string_t **propval_p,
Index: subversion/libsvn_wc/props.h
===================================================================
--- subversion/libsvn_wc/props.h	(revision 1423220)
+++ subversion/libsvn_wc/props.h	(working copy)
@@ -56,6 +56,14 @@ svn_wc__internal_propget(const svn_strin
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool);
 
+/* DB-internal version of svn_wc__set_props(), which see. */
+svn_error_t *
+svn_wc__internal_set_props(svn_wc__db_t *db,
+                           const char *local_abspath,
+                           const apr_hash_t *props,
+                           svn_boolean_t skip_checks,
+                           apr_pool_t *scratch_pool);
+
 
 /* Given LOCAL_ABSPATH/DB and an array of PROPCHANGES based on
    SERVER_BASEPROPS, calculate what changes should be applied to the working
Index: subversion/libsvn_wc/wc_db.c
===================================================================
--- subversion/libsvn_wc/wc_db.c	(revision 1423220)
+++ subversion/libsvn_wc/wc_db.c	(working copy)
@@ -4925,6 +4925,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
 svn_error_t *
 svn_wc__db_op_add_directory(svn_wc__db_t *db,
                             const char *local_abspath,
+                            const apr_hash_t *props,
                             const svn_skel_t *work_items,
                             apr_pool_t *scratch_pool)
 {
@@ -4948,6 +4949,11 @@ svn_wc__db_op_add_directory(svn_wc__db_t
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_kind_dir;
   iwb.op_depth = relpath_depth(local_relpath);
+  if (props)
+    {
+      iwb.update_actual_props = TRUE;
+      iwb.new_actual_props = props;
+    }
 
   iwb.work_items = work_items;
 
@@ -4965,6 +4971,7 @@ svn_wc__db_op_add_directory(svn_wc__db_t
 svn_error_t *
 svn_wc__db_op_add_file(svn_wc__db_t *db,
                        const char *local_abspath,
+                       const apr_hash_t *props,
                        const svn_skel_t *work_items,
                        apr_pool_t *scratch_pool)
 {
@@ -4988,6 +4995,11 @@ svn_wc__db_op_add_file(svn_wc__db_t *db,
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_kind_file;
   iwb.op_depth = relpath_depth(local_relpath);
+  if (props)
+    {
+      iwb.update_actual_props = TRUE;
+      iwb.new_actual_props = props;
+    }
 
   iwb.work_items = work_items;
 
@@ -5003,6 +5015,7 @@ svn_error_t *
 svn_wc__db_op_add_symlink(svn_wc__db_t *db,
                           const char *local_abspath,
                           const char *target,
+                          const apr_hash_t *props,
                           const svn_skel_t *work_items,
                           apr_pool_t *scratch_pool)
 {
@@ -5029,6 +5042,11 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_kind_symlink;
   iwb.op_depth = relpath_depth(local_relpath);
+  if (props)
+    {
+      iwb.update_actual_props = TRUE;
+      iwb.new_actual_props = props;
+    }
 
   iwb.target = target;
 
Index: subversion/libsvn_wc/wc_db.h
===================================================================
--- subversion/libsvn_wc/wc_db.h	(revision 1423220)
+++ subversion/libsvn_wc/wc_db.h	(working copy)
@@ -1383,16 +1383,18 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
 svn_error_t *
 svn_wc__db_op_add_directory(svn_wc__db_t *db,
                             const char *local_abspath,
+                            const apr_hash_t *props,
                             const svn_skel_t *work_items,
                             apr_pool_t *scratch_pool);
 
 
-/* ### as a new file, there are no properties. this file has no "pristine"
+/* ### this file has no "pristine"
    ### contents, so a checksum [reference] is not required.  */
 /* ### do we need a CONFLICTS param?  */
 svn_error_t *
 svn_wc__db_op_add_file(svn_wc__db_t *db,
                        const char *local_abspath,
+                       const apr_hash_t *props,
                        const svn_skel_t *work_items,
                        apr_pool_t *scratch_pool);
 
@@ -1403,6 +1405,7 @@ svn_error_t *
 svn_wc__db_op_add_symlink(svn_wc__db_t *db,
                           const char *local_abspath,
                           const char *target,
+                          const apr_hash_t *props,
                           const svn_skel_t *work_items,
                           apr_pool_t *scratch_pool);
 
Index: subversion/tests/libsvn_wc/conflict-data-test.c
===================================================================
--- subversion/tests/libsvn_wc/conflict-data-test.c	(revision 1423220)
+++ subversion/tests/libsvn_wc/conflict-data-test.c	(working copy)
@@ -202,8 +202,8 @@ test_read_write_tree_conflicts(const svn
 
   SVN_ERR(svn_test__sandbox_create(&sbox, "read_write_tree_conflicts", opts, pool));
   parent_abspath = svn_dirent_join(sbox.wc_abspath, "A", pool);
-  SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath, NULL,
-                                      pool));
+  SVN_ERR(svn_wc__db_op_add_directory(sbox.wc_ctx->db, parent_abspath,
+                                      NULL /*props*/, NULL, pool));
   child1_abspath = svn_dirent_join(parent_abspath, "foo", pool);
   child2_abspath = svn_dirent_join(parent_abspath, "bar", pool);
 
Index: subversion/tests/libsvn_wc/utils.c
===================================================================
--- subversion/tests/libsvn_wc/utils.c	(revision 1423220)
+++ subversion/tests/libsvn_wc/utils.c	(working copy)
@@ -174,7 +174,8 @@ sbox_wc_add(svn_test__sandbox_t *b, cons
   parent_abspath = svn_dirent_dirname(path, b->pool);
   SVN_ERR(svn_wc__acquire_write_lock(NULL, b->wc_ctx, parent_abspath, FALSE,
                                      b->pool, b->pool));
-  SVN_ERR(svn_wc_add_from_disk(b->wc_ctx, path, NULL, NULL, b->pool));
+  SVN_ERR(svn_wc_add_from_disk2(b->wc_ctx, path, NULL /*props*/,
+                                NULL, NULL, b->pool));
   SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, parent_abspath, b->pool));
   return SVN_NO_ERROR;
 }
