Index: subversion/include/svn_ra_svn.h
===================================================================
--- subversion/include/svn_ra_svn.h	(revision 14801)
+++ subversion/include/svn_ra_svn.h	(working copy)
@@ -267,6 +267,12 @@
                                           apr_pool_t *pool,
                                           const char *fmt, ...);
 
+/** Parse the error messages in @params from a command response with a
+ *  failure status and generate errors from its contents using @pool.
+ */
+svn_error_t *svn_ra_svn_handle_failure_status (apr_pool_t *pool,
+                                               apr_array_header_t *params);
+
 /** Accept commands over the network and handle them according to @a
  * commands.  Command handlers will be passed @a conn, a subpool of @a
  * pool (cleared after each command is handled), the parameters of the
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c	(revision 14801)
+++ subversion/libsvn_ra_svn/client.c	(working copy)
@@ -1396,7 +1396,7 @@
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *ra_svn_lock(svn_ra_session_t *session,
+static svn_error_t *ra_svn_lock0(svn_ra_session_t *session,
                                 apr_hash_t *path_revs,
                                 const char *comment,
                                 svn_boolean_t force,
@@ -1410,8 +1410,6 @@
   apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create (pool);
 
-  /* ### TODO for 1.3: Send all the locks over the wire at once.  This
-        loop is just a temporary shim. */
   for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
     {
       svn_lock_t *lock;
@@ -1459,7 +1457,110 @@
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *ra_svn_unlock(svn_ra_session_t *session,
+static svn_error_t *ra_svn_lock(svn_ra_session_t *session,
+                                apr_hash_t *path_revs,
+                                const char *comment,
+                                svn_boolean_t force,
+                                svn_ra_lock_callback_t lock_func, 
+                                void *lock_baton,
+                                apr_pool_t *pool)
+{
+  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn_conn_t* conn = sess->conn;
+  apr_array_header_t *list;
+  apr_hash_index_t *hi;
+  int i;
+  svn_ra_svn_item_t *elt;
+  svn_error_t *err, *callback_err = NULL;
+  apr_pool_t *subpool = svn_pool_create (pool);
+  const char *status;
+  apr_array_header_t *save_paths;   /* condensed target paths */
+  save_paths = apr_array_make(subpool, 1, sizeof(const char*));
+
+  /* (lock-many (?c) b ( (c(?r)) ...) ) */
+  // memory leak because subpool is not being destroyed?
+  SVN_ERR(svn_ra_svn_write_tuple(conn, subpool, "w((?c)b(!",
+                                 "lock-many", comment, force));
+
+  for (hi = apr_hash_first(subpool, path_revs); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      const char *path;
+      void *val;
+      svn_revnum_t *revnum;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      path = key;
+      APR_ARRAY_PUSH(save_paths, const char*) = path;
+      revnum = val;
+
+      SVN_ERR(svn_ra_svn_write_tuple(conn, subpool, "c(?r)",
+                                     path, *revnum));
+    }
+
+  SVN_ERR(svn_ra_svn_write_tuple(conn, subpool, "!))"));
+
+  err = handle_auth_request(sess, subpool);
+
+  /* Pre-1.3 servers don't support 'lock_many'. If that fails, fall back
+   * to 'lock'. */
+  if (err && err->apr_err == SVN_ERR_RA_SVN_UNKNOWN_CMD &&
+      strcmp (err->message, "Unknown command 'lock-many'") == 0)
+    {
+        svn_pool_destroy (subpool);
+        return ra_svn_lock0(session, path_revs, comment, force,
+                            lock_func, lock_baton, pool);
+    }
+
+  /* Servers before 1.2 doesn't support locking.  Check this here. */
+  SVN_ERR(handle_unsupported_cmd(err, _("Server doesn't support the "
+                                        "lock command")));
+
+  /* svn_ra_svn_read_cmd_response unusable as it doesn't
+   * return unparsed params. */
+  err = svn_ra_svn_read_tuple(conn, subpool, "wl", &status, &list);
+
+  /* Handle failure status explicitly */
+  if (strcmp (status, "failure") == 0)
+    {
+      return svn_ra_svn_handle_failure_status (subpool, list);
+    }
+
+  if (err && !SVN_ERR_IS_LOCK_ERROR (err))
+    return err;
+
+  for (i = 0; i < list->nelts; ++i)
+    {
+      svn_lock_t *lock;
+      const char *saved_path;
+
+      saved_path = APR_ARRAY_IDX(save_paths, i, const char *);
+      elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+
+      if (elt->kind != SVN_RA_SVN_LIST)
+        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                _("Lock element not a list"));
+
+      err = parse_lock(elt->u.list, subpool, &lock);
+      if (err)
+          return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, err,
+                                _("unable to parse lock data"));
+
+      if (lock_func) {
+        callback_err = lock_func(lock_baton, saved_path, TRUE,
+                                 err ? NULL : lock,
+                                 err, subpool); }
+
+      if (callback_err)
+        return callback_err;
+    }
+
+  svn_pool_destroy (subpool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *ra_svn_unlock0(svn_ra_session_t *session,
                                   apr_hash_t *path_tokens,
                                   svn_boolean_t force,
                                   svn_ra_lock_callback_t lock_func, 
@@ -1471,8 +1572,6 @@
   apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create (pool);
 
-  /* ### TODO for 1.3: Send all the lock tokens over the wire at once.
-        This loop is just a temporary shim. */
   for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi))
     {
       const void *key;
@@ -1517,6 +1616,89 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *ra_svn_unlock(svn_ra_session_t *session,
+                                  apr_hash_t *path_tokens,
+                                  svn_boolean_t force,
+                                  svn_ra_lock_callback_t lock_func, 
+                                  void *lock_baton,
+                                  apr_pool_t *pool)
+{
+  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn_conn_t* conn = sess->conn;
+  apr_hash_index_t *hi;
+  apr_pool_t *subpool = svn_pool_create (pool);
+  svn_error_t *err, *callback_err;
+
+  /* (unlock-many (b ( (c(?c)) ...) ) ) */
+  SVN_ERR(svn_ra_svn_write_tuple(conn, subpool, "w(b(!",
+                                 "unlock-many",force));
+  for (hi = apr_hash_first(subpool, path_tokens); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      const char *path;
+      void *val;
+      const char *token;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      path = key;
+
+      if (strcmp (val, "") != 0)
+        token = val;
+      else
+        token = NULL;
+       
+      SVN_ERR(svn_ra_svn_write_tuple(conn, subpool, "c(?c)",
+                                 path,token));
+    }
+  SVN_ERR(svn_ra_svn_write_tuple(conn,subpool,"!))"));
+
+  err = handle_auth_request(sess, subpool);
+
+  /* Pre-1.3 servers don't support 'unlock_many'. If unknown, fall back
+   * to 'unlock'.
+   */
+  if (err && err->apr_err == SVN_ERR_RA_SVN_UNKNOWN_CMD &&
+      strcmp (err->message, "Unknown command 'unlock-many'") == 0)
+    {
+      svn_error_clear (err);
+      return ra_svn_unlock0(session, path_tokens,
+                              force,lock_func,lock_baton,subpool);
+    }
+
+  /* Servers before 1.2 don't support locking.  Check this here. */
+  SVN_ERR(handle_unsupported_cmd(err, _("Server doesn't support the "
+                                        "unlock command")));
+
+  /* Unknown error */
+  if (err)
+    return err;
+
+  err = svn_ra_svn_read_cmd_response(conn, subpool, "");
+
+  if (err && !SVN_ERR_IS_UNLOCK_ERROR (err))
+    return err;
+ 
+  for (hi = apr_hash_first(subpool, path_tokens); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      const char *path;
+
+      apr_hash_this(hi, &key, NULL, NULL);
+      path = key;
+
+      if (lock_func)
+        callback_err =
+          lock_func(lock_baton, path, FALSE, NULL, err, subpool);
+      if (callback_err)
+        return callback_err;
+    }
+
+  svn_error_clear (err);
+  svn_pool_destroy (subpool);
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *ra_svn_get_lock(svn_ra_session_t *session,
                                     svn_lock_t **lock,
                                     const char *path,
@@ -1558,7 +1740,7 @@
 
   /* Servers before 1.2 doesn't support locking.  Check this here. */
   SVN_ERR(handle_unsupported_cmd(handle_auth_request(sess, pool),
-                                 _("Server doesn't support the get-lock "
+                                 _("Server doesn't support the get-locks "
                                    "command")));
 
   SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "l", &list));
@@ -1646,3 +1828,4 @@
 #define INITFUNC svn_ra_svn__init
 #define COMPAT_INITFUNC svn_ra_svn_init
 #include "../libsvn_ra/wrapper_template.h"
+
Index: subversion/libsvn_ra_svn/marshal.c
===================================================================
--- subversion/libsvn_ra_svn/marshal.c	(revision 14801)
+++ subversion/libsvn_ra_svn/marshal.c	(working copy)
@@ -741,17 +741,47 @@
 
 /* --- READING AND WRITING COMMANDS AND RESPONSES --- */
 
+svn_error_t *svn_ra_svn_handle_failure_status(apr_pool_t *pool,
+                                              apr_array_header_t *params)
+{
+  const char *message, *file;
+  svn_error_t *err;
+  svn_ra_svn_item_t *elt;
+  int i;
+  apr_uint64_t apr_err, line;
+
+  /* Rebuild the error list from the end, to avoid reversing the order. */
+  if (params->nelts == 0)
+    return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                            _("Empty error list"));
+  err = NULL;
+  for (i = params->nelts - 1; i >= 0; i--)
+    {
+      elt = &((svn_ra_svn_item_t *) params->elts)[i];
+      if (elt->kind != SVN_RA_SVN_LIST)
+        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                _("Malformed error list"));
+      SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "nccn", &apr_err,
+                                      &message, &file, &line));
+      /* The message field should have been optional, but we can't
+         easily change that, so "" means a nonexistent message. */
+      if (!*message)
+        message = NULL;
+      err = svn_error_create(apr_err, err, message);
+      err->file = apr_pstrdup(err->pool, file);
+      err->line = line;
+    }
+  return err;
+}
+
 svn_error_t *svn_ra_svn_read_cmd_response(svn_ra_svn_conn_t *conn,
                                           apr_pool_t *pool,
                                           const char *fmt, ...)
 {
   va_list ap;
-  const char *status, *message, *file;
+  const char *status;
   apr_array_header_t *params;
   svn_error_t *err;
-  svn_ra_svn_item_t *elt;
-  int i;
-  apr_uint64_t apr_err, line;
 
   SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "wl", &status, &params));
   if (strcmp(status, "success") == 0)
@@ -763,28 +793,7 @@
     }
   else if (strcmp(status, "failure") == 0)
     {
-      /* Rebuild the error list from the end, to avoid reversing the order. */
-      if (params->nelts == 0)
-        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
-                                _("Empty error list"));
-      err = NULL;
-      for (i = params->nelts - 1; i >= 0; i--)
-        {
-          elt = &((svn_ra_svn_item_t *) params->elts)[i];
-          if (elt->kind != SVN_RA_SVN_LIST)
-            return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
-                                    _("Malformed error list"));
-          SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "nccn", &apr_err,
-                                          &message, &file, &line));
-          /* The message field should have been optional, but we can't
-             easily change that, so "" means a nonexistent message. */
-          if (!*message)
-            message = NULL;
-          err = svn_error_create(apr_err, err, message);
-          err->file = apr_pstrdup(err->pool, file);
-          err->line = line;
-        }
-      return err;
+      return svn_ra_svn_handle_failure_status (pool, params);
     }
 
   return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c	(revision 14801)
+++ subversion/svnserve/serve.c	(working copy)
@@ -1377,6 +1377,15 @@
   return SVN_NO_ERROR;
 }
 
+static const char* e2s (int e)
+{
+   if ( e == SVN_RA_SVN_NUMBER) return "SVN_RA_SVN_NUMBER";
+   else if ( e == SVN_RA_SVN_STRING) return "SVN_RA_SVN_STRING";
+   else if ( e == SVN_RA_SVN_WORD) return "SVN_RA_SVN_WORD";
+   else if ( e == SVN_RA_SVN_LIST) return "SVN_RA_SVN_LIST";
+   else return "UNKNOWN enum";
+}
+
 static svn_error_t *lock(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                          apr_array_header_t *params, void *baton)
 {
@@ -1407,6 +1416,80 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *lock_many(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                         apr_array_header_t *params, void *baton)
+{
+  apr_array_header_t *locks;
+  apr_array_header_t *lock_cmds;
+  server_baton_t *b = baton;
+  const char *comment;
+  svn_boolean_t force;
+  int i;
+  struct lock_cmd {
+    const char *path;
+    const char *full_path;
+    svn_revnum_t current_rev;
+    svn_lock_t *l;
+  };
+
+  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "(?c)bl", &comment, &force, &locks));
+
+  lock_cmds =
+    apr_array_make(pool, locks->nelts, sizeof(struct lock_cmd));
+
+  /* Loop through the lock commands */
+  for (i = 0; i < locks->nelts; ++i)
+    {
+      fprintf (stderr, "IN LOOP: number of elements in locks list: %d\n", 
+               locks->nelts);
+      struct lock_cmd *cmd = apr_pcalloc(pool, sizeof(struct lock_cmd));
+      svn_ra_svn_item_t *item =
+        &APR_ARRAY_IDX(locks, i, svn_ra_svn_item_t);
+
+      if (item->kind != SVN_RA_SVN_LIST)
+        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                "Lock commands should be list of lists\n");
+
+
+      SVN_ERR(svn_ra_svn_parse_tuple(item->u.list, pool, "c(?r)",
+                                     &cmd->path, &cmd->current_rev));
+
+      cmd->full_path = svn_path_join(b->fs_path,
+                                svn_path_canonicalize(cmd->path, pool),
+                                pool);
+
+      APR_ARRAY_PUSH(lock_cmds, struct lock_cmd) = *cmd;
+    }
+
+  SVN_ERR(must_have_write_access(conn, pool, b, TRUE));
+
+  /* Loop through each path to be locked */
+  for (i = 0; i < lock_cmds->nelts; i++)
+    {
+      struct lock_cmd *cmd =
+        &APR_ARRAY_IDX(lock_cmds, i, struct lock_cmd);
+
+      SVN_CMD_ERR(
+        svn_repos_fs_lock(&cmd->l, b->repos, cmd->full_path,
+                          NULL, comment, 0,
+                          0, /* No expiration time. */
+                          cmd->current_rev,
+                          force, pool));
+    }
+
+  /* (success( (ccc(?c)c(?c) ... )) */
+  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(!", "success"));
+  for (i = 0; i < lock_cmds->nelts; i++)
+    {
+      struct lock_cmd *cmd =
+        &APR_ARRAY_IDX(lock_cmds, i, struct lock_cmd);
+      SVN_ERR(write_lock(conn, pool, cmd->l));
+    }
+  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)"));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *unlock(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                            apr_array_header_t *params, void *baton)
 {
@@ -1419,7 +1502,7 @@
 
   full_path = svn_path_join(b->fs_path, svn_path_canonicalize(path, pool),
                             pool);
-
+  fprintf(stderr,"Here is the full path:%s",full_path);
   /* Username required unless force was specified. */
   SVN_ERR(must_have_write_access(conn, pool, b, ! force));
 
@@ -1430,6 +1513,55 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *unlock_many(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                           apr_array_header_t *params, void *baton)
+{
+  server_baton_t *b = baton;
+  svn_boolean_t force;
+  apr_array_header_t *unlock_tokens;
+  apr_array_header_t *unlock_cmds;
+  struct unlock_cmd {
+    const char *path;
+    const char *token;
+    const char *full_path;
+  };
+  int i;
+ 
+  SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "bl",&force, &unlock_tokens));
+
+  unlock_cmds =
+    apr_array_make(pool, unlock_tokens->nelts, sizeof(struct unlock_cmd));
+
+  for(i = 0; i< unlock_tokens->nelts; i++)
+    {
+      struct unlock_cmd *cmd = apr_pcalloc(pool,sizeof(struct unlock_cmd));
+      svn_ra_svn_item_t *item = &APR_ARRAY_IDX(unlock_tokens, i,
+                                 svn_ra_svn_item_t); 
+      if (item->kind != SVN_RA_SVN_LIST)
+        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                "Unlock command should be a list of lists\n");
+      SVN_ERR(svn_ra_svn_parse_tuple(item->u.list, pool, "c(?c)",
+                                     &cmd->path, &cmd->token));
+      cmd->full_path = svn_path_join(b->fs_path,
+                       svn_path_canonicalize(cmd->path, pool),pool);
+      APR_ARRAY_PUSH(unlock_cmds, struct unlock_cmd) = *cmd;
+    }
+
+  /* Username required unless force was specified. */
+  SVN_ERR(must_have_write_access(conn, pool, b, ! force));
+  for (i = 0; i < unlock_tokens->nelts; i++)
+    {
+      struct unlock_cmd *cmd = &APR_ARRAY_IDX(unlock_cmds, i, 
+                                              struct unlock_cmd); 
+      SVN_CMD_ERR(svn_repos_fs_unlock(b->repos, cmd->full_path, 
+                                  cmd->token, force, pool));
+    }
+
+  SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *get_lock(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                              apr_array_header_t *params, void *baton)
 {
@@ -1509,7 +1641,9 @@
   { "get-locations",   get_locations },
   { "get-file-revs",   get_file_revs },
   { "lock",            lock },
+  { "lock-many",       lock_many },
   { "unlock",          unlock },
+  { "unlock-many",     unlock_many },
   { "get-lock",        get_lock },
   { "get-locks",       get_locks },
   { NULL }


