Index: subversion/clients/cmdline/lock-cmd.c
===================================================================
--- subversion/clients/cmdline/lock-cmd.c	(revision 0)
+++ subversion/clients/cmdline/lock-cmd.c	(revision 0)
@@ -0,0 +1,221 @@
+/*
+ * lock-cmd.c -- Lock files exclusively
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_private_config.h"
+#include "svn_cmdline.h"
+#include "svn_wc.h"
+#include "svn_pools.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_path.h"
+#include "svn_delta.h"
+#include "svn_error.h"
+#include "svn_utf.h"
+#include "svn_subst.h"
+#include "svn_private_config.h"
+#include "svn_auth.h"
+#include "svn_ra.h"
+#include "svn_base64.h"
+#include "cl.h"
+
+#include "svn_private_config.h"
+
+
+/*** Code. ***/
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__lock (apr_getopt_t *os,
+                  void *baton,
+                  apr_pool_t *pool)
+{
+  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) 
baton)->opt_state;
+  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
+
+  apr_pool_t *subpool = svn_pool_create (pool);
+  const char *pname, *pname_utf8, *URL;
+  apr_array_header_t *args, *targets, *condensed_targets;
+  int i, j;
+
+  /* ra stuff */
+  void *ra_baton, *session, *report_baton;
+  svn_ra_plugin_t *ra_lib;
+  const char* reposPath;
+  svn_revnum_t rev;
+  svn_string_t *cur_lock_owner;
+
+
+  /* Suck up all the remaining arguments into a targets array */
+  SVN_ERR (svn_opt_args_to_target_array (&targets, os,
+                                         opt_state->targets,
+                                         &(opt_state->start_revision),
+                                         &(opt_state->end_revision),
+                                         FALSE, pool));
+
+  /* Add "." if user passed 0 arguments. */
+  svn_opt_push_implicit_dot_target (targets, pool);
+
+  /* Remove redundancies from the target list while preserving order. */
+  SVN_ERR (svn_path_remove_redundancies (&condensed_targets,
+                                         targets,
+                                         pool));
+
+  /** init RA layer lib */
+  SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
+
+  for (i = 0; i < condensed_targets->nelts; i++)
+    {
+      const char *target = ((const char **) (targets->elts))[i];
+      svn_wc_adm_access_t *adm_access;
+      const svn_wc_entry_t *entry;
+
+      svn_pool_clear (subpool);
+      SVN_ERR(svn_cl__check_cancel (ctx->cancel_baton));
+
+      /* Make sure we're attempting to lock a versioned resource */
+      SVN_ERR (svn_wc_adm_probe_open2 (&adm_access, NULL, target, FALSE,
+                                        opt_state->recursive ? -1 : 0,
+                                        subpool));
+
+      SVN_ERR (svn_wc_entry (&entry, target, adm_access, FALSE, subpool));
+      if (! entry)
+        {
+          SVN_ERR (svn_cmdline_printf
+                    (subpool, _("Could not lock %s: Not a versioned 
resource\n"),
+                    svn_path_local_style (target, pool)));
+          continue;
+        }
+      else if (entry->kind == svn_node_dir)
+        {
+          SVN_ERR(svn_cmdline_printf( subpool,
+                                      _("Could not lock '%s'; Directories 
can not be locked\n"),
+                                      target));
+          continue;
+        }
+
+      /* Convert URL */
+      SVN_ERR (svn_client_url_from_path (&URL, target, subpool));
+      if (URL == NULL)
+        {
+            SVN_ERR(svn_cmdline_printf(subpool, _("Unable to lock '%s'\n"), 
target));
+            continue;
+        }
+
+
+
+      /* Get the RA library that handles this URL schema. */
+      SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, URL, subpool));
+
+      /* Open a repository session to the URL. */
+      SVN_ERR ((svn_error_t*)svn_client__open_ra_session (&session, ra_lib, 
URL, NULL,
+                                            NULL, NULL, TRUE, TRUE,
+                                            ctx, subpool));
+
+      /* Get root part of URL, e.g. http://myserver/svn/myrepos */
+      ra_lib->get_repos_root(session, &reposPath, subpool);
+
+      /* Get path relative to repos-root,
+        i.e. from 'http://myserver/svn/repos/my/path' to 'my/path' */
+      svn_string_t *repos_rel_path = svn_string_create((const 
char*)&URL[strlen(reposPath)+1], subpool);
+
+      /* Base64 encode and get rid of =+\n to make the propname "human 
readable" */
+      svn_stringbuf_t *encoded_path = svn_stringbuf_create_from_string(
+                                      
svn_base64_encode_string(repos_rel_path, subpool), subpool);
+
+      for (j=0; j < encoded_path->len; j++)
+        {
+          encoded_path->data[j] = ( encoded_path->data[j] == '\n' ||
+                                    encoded_path->data[j] == '='  ||
+                                    encoded_path->data[j] == '+')
+                                    ? '-' : encoded_path->data[j];
+        }
+
+      /* Create property name in the form Flock-BASE64(/path/in/repos)
+         The F-prefix is 1 if forcing the lock and 0 if not. The flag byte 
will
+         be removed by the hook so the final propname is 
lock-BASE64(/path/in/repos)
+
+         The prefix trick is due to a bug in pre-1.1 that prevents 
pre-revprop-change
+         scripts of getting hold of the propvalue. Once the fix for that
+         is released, a nicer solution might be to pass the force
+         flag as the propvalue. */
+      svn_stringbuf_t *lock_token = svn_stringbuf_create((opt_state->force 
? "F" : "N"), subpool);
+      svn_stringbuf_appendcstr(lock_token, "lock-");
+
+      /* Append the encoded path, and we're done constructing the lock 
token */
+      svn_stringbuf_appendstr(lock_token, encoded_path);
+
+      /* For the sake of completeness */
+      SVN_ERR (svn_utf_cstring_to_utf8 (&pname_utf8, lock_token->data, 
subpool));
+
+      /* Lock tokens are stored in rev 0 */
+      svn_opt_revision_t rev0;
+      rev0.kind = svn_opt_revision_number;
+      rev0.value.number = 0;
+
+      /* Fetch the current property */
+      svn_error_t *err = svn_client_revprop_get (&pname_utf8[1],  /* drop 
force flag */
+                                                 &cur_lock_owner,
+                                                 URL, &rev0,
+                                                 &rev, ctx, subpool);
+      if (err)
+        {
+          SVN_ERR(svn_cmdline_printf(subpool, _("Getting current lock owner 
failed: '%s'\n"), err->message));
+        }
+
+      /* Set lock-owner. This will fail the in pre-revprop-change hook
+         if the resource is locked by another user. If authentication is
+         OK (or --force), the hook will set the revprop value = username */
+      err = svn_client_revprop_set (pname_utf8,
+                                    /* must supply a value, or the hook 
won't be called */
+                                    svn_string_create( "ignore", subpool),
+                                    URL, &rev0,
+                                    &rev, TRUE,
+                                    ctx, subpool);
+
+      if (err)
+        {
+          if(!cur_lock_owner || !cur_lock_owner->data)
+            SVN_ERR(svn_cmdline_printf(subpool, _("Setting lock failed and 
unable to obtain lock owner for %s (%s): %s\n"), target, &pname_utf8[1], 
err->message));
+          else
+	          /* this won't happend if the lock is --force'ed */
+            SVN_ERR(svn_cmdline_printf(subpool, _("Could not lock %s: 
Already locked by '%s'\n"), target, cur_lock_owner->data));
+        }
+      else
+        {
+          SVN_ERR(svn_cmdline_printf(subpool, _("Successfully locked %s"), 
target));
+
+          /* Print lock token in verbose mode */
+          if(opt_state->verbose)
+            SVN_ERR(svn_cmdline_printf(subpool, _(" (%s)\n"), 
&pname_utf8[1]));
+          else
+            SVN_ERR(svn_cmdline_printf(subpool, _("\n"), target));
+
+        }
+
+  }/* for each target */
+
+  svn_pool_destroy (subpool);
+
+  return SVN_NO_ERROR;
+}


