subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From v...@apache.org
Subject svn commit: r1426654 [5/7] - in /subversion/branches/javahl-ra: ./ build/ build/ac-macros/ subversion/bindings/cxxhl/include/svncxxhl/ subversion/bindings/cxxhl/src/ subversion/bindings/cxxhl/tests/ subversion/include/ subversion/include/private/ subve...
Date Fri, 28 Dec 2012 23:03:53 GMT
Modified: subversion/branches/javahl-ra/subversion/svn/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svn/util.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svn/util.c (original)
+++ subversion/branches/javahl-ra/subversion/svn/util.c Fri Dec 28 23:03:51 2012
@@ -62,6 +62,7 @@
 #include "private/svn_token.h"
 #include "private/svn_opt_private.h"
 #include "private/svn_client_private.h"
+#include "private/svn_cmdline_private.h"
 #include "private/svn_string_private.h"
 
 
@@ -93,125 +94,6 @@ svn_cl__print_commit_info(const svn_comm
 }
 
 
-/* Helper for the next two functions.  Set *EDITOR to some path to an
-   editor binary.  Sources to search include: the EDITOR_CMD argument
-   (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
-   is not NULL), $VISUAL, $EDITOR.  Return
-   SVN_ERR_CL_NO_EXTERNAL_EDITOR if no binary can be found. */
-static svn_error_t *
-find_editor_binary(const char **editor,
-                   const char *editor_cmd,
-                   apr_hash_t *config)
-{
-  const char *e;
-  struct svn_config_t *cfg;
-
-  /* Use the editor specified on the command line via --editor-cmd, if any. */
-  e = editor_cmd;
-
-  /* Otherwise look for the Subversion-specific environment variable. */
-  if (! e)
-    e = getenv("SVN_EDITOR");
-
-  /* If not found then fall back on the config file. */
-  if (! e)
-    {
-      cfg = config ? apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG,
-                                  APR_HASH_KEY_STRING) : NULL;
-      svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
-                     SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
-    }
-
-  /* If not found yet then try general purpose environment variables. */
-  if (! e)
-    e = getenv("VISUAL");
-  if (! e)
-    e = getenv("EDITOR");
-
-#ifdef SVN_CLIENT_EDITOR
-  /* If still not found then fall back on the hard-coded default. */
-  if (! e)
-    e = SVN_CLIENT_EDITOR;
-#endif
-
-  /* Error if there is no editor specified */
-  if (e)
-    {
-      const char *c;
-
-      for (c = e; *c; c++)
-        if (!svn_ctype_isspace(*c))
-          break;
-
-      if (! *c)
-        return svn_error_create
-          (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
-           _("The EDITOR, SVN_EDITOR or VISUAL environment variable or "
-             "'editor-cmd' run-time configuration option is empty or "
-             "consists solely of whitespace. Expected a shell command."));
-    }
-  else
-    return svn_error_create
-      (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
-       _("None of the environment variables SVN_EDITOR, VISUAL or EDITOR are "
-         "set, and no 'editor-cmd' run-time configuration option was found"));
-
-  *editor = e;
-  return SVN_NO_ERROR;
-}
-
-
-/* Use the visual editor to edit files. This requires that the file name itself
-   be shell-safe, although the path to reach that file need not be shell-safe.
- */
-svn_error_t *
-svn_cl__edit_file_externally(const char *path,
-                             const char *editor_cmd,
-                             apr_hash_t *config,
-                             apr_pool_t *pool)
-{
-  const char *editor, *cmd, *base_dir, *file_name, *base_dir_apr;
-  char *old_cwd;
-  int sys_err;
-  apr_status_t apr_err;
-
-  svn_dirent_split(&base_dir, &file_name, path, pool);
-
-  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
-
-  apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
-  if (apr_err)
-    return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
-
-  /* APR doesn't like "" directories */
-  if (base_dir[0] == '\0')
-    base_dir_apr = ".";
-  else
-    SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
-
-  apr_err = apr_filepath_set(base_dir_apr, pool);
-  if (apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Can't change working directory to '%s'"), base_dir);
-
-  cmd = apr_psprintf(pool, "%s %s", editor, file_name);
-  sys_err = system(cmd);
-
-  apr_err = apr_filepath_set(old_cwd, pool);
-  if (apr_err)
-    svn_handle_error2(svn_error_wrap_apr
-                      (apr_err, _("Can't restore working directory")),
-                      stderr, TRUE /* fatal */, "svn: ");
-
-  if (sys_err)
-    /* Extracting any meaning from sys_err is platform specific, so just
-       use the raw value. */
-    return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
-                             _("system('%s') returned %d"), cmd, sys_err);
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_cl__merge_file_externally(const char *base_path,
                               const char *their_path,
@@ -290,248 +172,6 @@ svn_cl__merge_file_externally(const char
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_cl__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
-                               const char **tmpfile_left /* UTF-8! */,
-                               const char *editor_cmd,
-                               const char *base_dir /* UTF-8! */,
-                               const svn_string_t *contents /* UTF-8! */,
-                               const char *filename,
-                               apr_hash_t *config,
-                               svn_boolean_t as_text,
-                               const char *encoding,
-                               apr_pool_t *pool)
-{
-  const char *editor;
-  const char *cmd;
-  apr_file_t *tmp_file;
-  const char *tmpfile_name;
-  const char *tmpfile_native;
-  const char *tmpfile_apr, *base_dir_apr;
-  svn_string_t *translated_contents;
-  apr_status_t apr_err, apr_err2;
-  apr_size_t written;
-  apr_finfo_t finfo_before, finfo_after;
-  svn_error_t *err = SVN_NO_ERROR, *err2;
-  char *old_cwd;
-  int sys_err;
-  svn_boolean_t remove_file = TRUE;
-
-  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
-
-  /* Convert file contents from UTF-8/LF if desired. */
-  if (as_text)
-    {
-      const char *translated;
-      SVN_ERR(svn_subst_translate_cstring2(contents->data, &translated,
-                                           APR_EOL_STR, FALSE,
-                                           NULL, FALSE, pool));
-      translated_contents = svn_string_create_empty(pool);
-      if (encoding)
-        SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated_contents->data,
-                                              translated, encoding, pool));
-      else
-        SVN_ERR(svn_utf_cstring_from_utf8(&translated_contents->data,
-                                          translated, pool));
-      translated_contents->len = strlen(translated_contents->data);
-    }
-  else
-    translated_contents = svn_string_dup(contents, pool);
-
-  /* Move to BASE_DIR to avoid getting characters that need quoting
-     into tmpfile_name */
-  apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
-  if (apr_err)
-    return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
-
-  /* APR doesn't like "" directories */
-  if (base_dir[0] == '\0')
-    base_dir_apr = ".";
-  else
-    SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
-  apr_err = apr_filepath_set(base_dir_apr, pool);
-  if (apr_err)
-    {
-      return svn_error_wrap_apr
-        (apr_err, _("Can't change working directory to '%s'"), base_dir);
-    }
-
-  /*** From here on, any problems that occur require us to cd back!! ***/
-
-  /* Ask the working copy for a temporary file named FILENAME-something. */
-  err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
-                                   "" /* dirpath */,
-                                   filename,
-                                   ".tmp",
-                                   svn_io_file_del_none, pool, pool);
-
-  if (err && (APR_STATUS_IS_EACCES(err->apr_err) || err->apr_err == EROFS))
-    {
-      const char *temp_dir_apr;
-
-      svn_error_clear(err);
-
-      SVN_ERR(svn_io_temp_dir(&base_dir, pool));
-
-      SVN_ERR(svn_path_cstring_from_utf8(&temp_dir_apr, base_dir, pool));
-      apr_err = apr_filepath_set(temp_dir_apr, pool);
-      if (apr_err)
-        {
-          return svn_error_wrap_apr
-            (apr_err, _("Can't change working directory to '%s'"), base_dir);
-        }
-
-      err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
-                                       "" /* dirpath */,
-                                       filename,
-                                       ".tmp",
-                                       svn_io_file_del_none, pool, pool);
-    }
-
-  if (err)
-    goto cleanup2;
-
-  /*** From here on, any problems that occur require us to cleanup
-       the file we just created!! ***/
-
-  /* Dump initial CONTENTS to TMP_FILE. */
-  apr_err = apr_file_write_full(tmp_file, translated_contents->data,
-                                translated_contents->len, &written);
-
-  apr_err2 = apr_file_close(tmp_file);
-  if (! apr_err)
-    apr_err = apr_err2;
-
-  /* Make sure the whole CONTENTS were written, else return an error. */
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't write to '%s'"),
-                               tmpfile_name);
-      goto cleanup;
-    }
-
-  err = svn_path_cstring_from_utf8(&tmpfile_apr, tmpfile_name, pool);
-  if (err)
-    goto cleanup;
-
-  /* Get information about the temporary file before the user has
-     been allowed to edit its contents. */
-  apr_err = apr_stat(&finfo_before, tmpfile_apr,
-                     APR_FINFO_MTIME, pool);
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
-      goto cleanup;
-    }
-
-  /* Backdate the file a little bit in case the editor is very fast
-     and doesn't change the size.  (Use two seconds, since some
-     filesystems have coarse granularity.)  It's OK if this call
-     fails, so we don't check its return value.*/
-  apr_file_mtime_set(tmpfile_apr, finfo_before.mtime - 2000, pool);
-
-  /* Stat it again to get the mtime we actually set. */
-  apr_err = apr_stat(&finfo_before, tmpfile_apr,
-                     APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
-      goto cleanup;
-    }
-
-  /* Prepare the editor command line.  */
-  err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
-  if (err)
-    goto cleanup;
-  cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);
-
-  /* If the caller wants us to leave the file around, return the path
-     of the file we'll use, and make a note not to destroy it.  */
-  if (tmpfile_left)
-    {
-      *tmpfile_left = svn_dirent_join(base_dir, tmpfile_name, pool);
-      remove_file = FALSE;
-    }
-
-  /* Now, run the editor command line.  */
-  sys_err = system(cmd);
-  if (sys_err != 0)
-    {
-      /* Extracting any meaning from sys_err is platform specific, so just
-         use the raw value. */
-      err =  svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
-                               _("system('%s') returned %d"), cmd, sys_err);
-      goto cleanup;
-    }
-
-  /* Get information about the temporary file after the assumed editing. */
-  apr_err = apr_stat(&finfo_after, tmpfile_apr,
-                     APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
-      goto cleanup;
-    }
-
-  /* If the file looks changed... */
-  if ((finfo_before.mtime != finfo_after.mtime) ||
-      (finfo_before.size != finfo_after.size))
-    {
-      svn_stringbuf_t *edited_contents_s;
-      err = svn_stringbuf_from_file2(&edited_contents_s, tmpfile_name, pool);
-      if (err)
-        goto cleanup;
-
-      *edited_contents = svn_stringbuf__morph_into_string(edited_contents_s);
-
-      /* Translate back to UTF8/LF if desired. */
-      if (as_text)
-        {
-          err = svn_subst_translate_string2(edited_contents, FALSE, FALSE,
-                                            *edited_contents, encoding, FALSE,
-                                            pool, pool);
-          if (err)
-            {
-              err = svn_error_quick_wrap
-                (err,
-                 _("Error normalizing edited contents to internal format"));
-              goto cleanup;
-            }
-        }
-    }
-  else
-    {
-      /* No edits seem to have been made */
-      *edited_contents = NULL;
-    }
-
- cleanup:
-  if (remove_file)
-    {
-      /* Remove the file from disk.  */
-      err2 = svn_io_remove_file2(tmpfile_name, FALSE, pool);
-
-      /* Only report remove error if there was no previous error. */
-      if (! err && err2)
-        err = err2;
-      else
-        svn_error_clear(err2);
-    }
-
- cleanup2:
-  /* If we against all probability can't cd back, all further relative
-     file references would be screwed up, so we have to abort. */
-  apr_err = apr_filepath_set(old_cwd, pool);
-  if (apr_err)
-    {
-      svn_handle_error2(svn_error_wrap_apr
-                        (apr_err, _("Can't restore working directory")),
-                        stderr, TRUE /* fatal */, "svn: ");
-    }
-
-  return svn_error_trace(err);
-}
-
 
 /* A svn_client_ctx_t's log_msg_baton3, for use with
    svn_cl__make_log_msg_baton(). */
@@ -732,8 +372,8 @@ svn_cl__get_log_message(const char **log
   while (! message)
     {
       /* We still don't have a valid commit message.  Use $EDITOR to
-         get one.  Note that svn_cl__edit_externally will still return
-         a UTF-8'ized log message. */
+         get one.  Note that svn_cl__edit_string_externally will still
+         return a UTF-8'ized log message. */
       int i;
       svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool);
       svn_error_t *err = SVN_NO_ERROR;
@@ -793,12 +433,12 @@ svn_cl__get_log_message(const char **log
       /* Use the external edit to get a log message. */
       if (! lmb->non_interactive)
         {
-          err = svn_cl__edit_string_externally(&msg_string, &lmb->tmpfile_left,
-                                               lmb->editor_cmd, lmb->base_dir,
-                                               msg_string, "svn-commit",
-                                               lmb->config, TRUE,
-                                               lmb->message_encoding,
-                                               pool);
+          err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left,
+                                                    lmb->editor_cmd, lmb->base_dir,
+                                                    msg_string, "svn-commit",
+                                                    lmb->config, TRUE,
+                                                    lmb->message_encoding,
+                                                    pool);
         }
       else /* non_interactive flag says we can't pop up an editor, so error */
         {

Modified: subversion/branches/javahl-ra/subversion/svnadmin/svnadmin.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnadmin/svnadmin.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnadmin/svnadmin.c (original)
+++ subversion/branches/javahl-ra/subversion/svnadmin/svnadmin.c Fri Dec 28 23:03:51 2012
@@ -1,5 +1,5 @@
 /*
- * main.c: Subversion server administration tool.
+ * svnadmin.c: Subversion server administration tool main file.
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one

Modified: subversion/branches/javahl-ra/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svndumpfilter/svndumpfilter.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/javahl-ra/subversion/svndumpfilter/svndumpfilter.c Fri Dec 28 23:03:51 2012
@@ -1,5 +1,5 @@
 /*
- * main.c: Subversion dump stream filtering tool.
+ * svndumpfilter.c: Subversion dump stream filtering tool main file.
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one

Modified: subversion/branches/javahl-ra/subversion/svnlook/svnlook.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnlook/svnlook.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnlook/svnlook.c (original)
+++ subversion/branches/javahl-ra/subversion/svnlook/svnlook.c Fri Dec 28 23:03:51 2012
@@ -1,5 +1,5 @@
 /*
- * main.c: Subversion server inspection tool.
+ * svnlook.c: Subversion server inspection tool main file.
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one

Modified: subversion/branches/javahl-ra/subversion/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnmucc/svnmucc.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnmucc/svnmucc.c (original)
+++ subversion/branches/javahl-ra/subversion/svnmucc/svnmucc.c Fri Dec 28 23:03:51 2012
@@ -55,6 +55,9 @@
 
 #include "private/svn_cmdline_private.h"
 #include "private/svn_ra_private.h"
+#include "private/svn_string_private.h"
+
+#include "svn_private_config.h"
 
 static void handle_error(svn_error_t *err, apr_pool_t *pool)
 {
@@ -750,6 +753,29 @@ execute(const apr_array_header_t *action
                                             "svnmucc: ", "--config-option"));
   cfg_config = apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG,
                             APR_HASH_KEY_STRING);
+
+  if (! apr_hash_get(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING))
+    {
+      svn_string_t *msg = svn_string_create("", pool);
+
+      /* If we can do so, try to pop up $EDITOR to fetch a log message. */
+      if (non_interactive)
+        {
+          return svn_error_create
+            (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
+             _("Cannot invoke editor to get log message "
+               "when non-interactive"));
+        }
+      else
+        {
+          SVN_ERR(svn_cmdline__edit_string_externally(
+                      &msg, NULL, NULL, "", msg, "svnmucc-commit", config,
+                      TRUE, NULL, apr_hash_pool_get(revprops)));
+        }
+
+      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING, msg);
+    }
+
   SVN_ERR(create_ra_callbacks(&ra_callbacks, username, password, config_dir,
                               cfg_config, non_interactive, no_auth_cache,
                               pool));
@@ -899,37 +925,42 @@ static void
 usage(apr_pool_t *pool, int exit_val)
 {
   FILE *stream = exit_val == EXIT_SUCCESS ? stdout : stderr;
-  static const char *msg =
-    "Multiple URL Command Client (for Subversion)\n"
-    "\nUsage: svnmucc [OPTION]... [ACTION]...\n"
-    "\nActions:\n"
-    "  cp REV URL1 URL2      copy URL1@REV to URL2\n"
-    "  mkdir URL             create new directory URL\n"
-    "  mv URL1 URL2          move URL1 to URL2\n"
-    "  rm URL                delete URL\n"
-    "  put SRC-FILE URL      add or modify file URL with contents copied from\n"
-    "                        SRC-FILE (use \"-\" to read from standard input)\n"
-    "  propset NAME VAL URL  set property NAME on URL to value VAL\n"
-    "  propsetf NAME VAL URL set property NAME on URL to value from file VAL\n"
-    "  propdel NAME URL      delete property NAME from URL\n"
-    "\nOptions:\n"
-    "  -h, --help, -?        display this text\n"
-    "  -m, --message ARG     use ARG as a log message\n"
-    "  -F, --file ARG        read log message from file ARG\n"
-    "  -u, --username ARG    commit the changes as username ARG\n"
-    "  -p, --password ARG    use ARG as the password\n"
-    "  -U, --root-url ARG    interpret all action URLs are relative to ARG\n"
-    "  -r, --revision ARG    use revision ARG as baseline for changes\n"
-    "  --with-revprop A[=B]  set revision property A in new revision to B\n"
-    "                        if specified, else to the empty string\n"
-    "  -n, --non-interactive don't prompt the user about anything\n"
-    "  -X, --extra-args ARG  append arguments from file ARG (one per line;\n"
-    "                        use \"-\" to read from standard input)\n"
-    "  --config-dir ARG      use ARG to override the config directory\n"
-    "  --config-option ARG   use ARG to override a configuration option\n"
-    "  --no-auth-cache       do not cache authentication tokens\n"
-    "  --version             print version information\n";
-  svn_error_clear(svn_cmdline_fputs(msg, stream, pool));
+  svn_error_clear(svn_cmdline_fputs(
+    _("Subversion multiple URL command client\n"
+      "usage: svnmucc [OPTION]... [ACTION]...\n"
+      "\n"
+      "  Perform one or more Subversion repository URL-based ACTIONs, committing\n"
+      "  the result as a (single) new revision.\n"
+      "\n"
+      "Actions:\n"
+      "  cp REV URL1 URL2       : copy URL1@REV to URL2\n"
+      "  mkdir URL              : create new directory URL\n"
+      "  mv URL1 URL2           : move URL1 to URL2\n"
+      "  rm URL                 : delete URL\n"
+      "  put SRC-FILE URL       : add or modify file URL with contents copied from\n"
+      "                           SRC-FILE (use \"-\" to read from standard input)\n"
+      "  propset NAME VAL URL   : set property NAME on URL to value VAL\n"
+      "  propsetf NAME VAL URL  : set property NAME on URL to value from file VAL\n"
+      "  propdel NAME URL       : delete property NAME from URL\n"
+      "\n"
+      "Valid options:\n"
+      "  -h, -? [--help]        : display this text\n"
+      "  -m [--message] ARG     : use ARG as a log message\n"
+      "  -F [--file] ARG        : read log message from file ARG\n"
+      "  -u [--username] ARG    : commit the changes as username ARG\n"
+      "  -p [--password] ARG    : use ARG as the password\n"
+      "  -U [--root-url] ARG    : interpret all action URLs relative to ARG\n"
+      "  -r [--revision] ARG    : use revision ARG as baseline for changes\n"
+      "  --with-revprop ARG     : set revision property in the following format:\n"
+      "                               NAME[=VALUE]\n"
+      "  -n [--non-interactive] : don't prompt the user about anything\n"
+      "  -X [--extra-args] ARG  : append arguments from file ARG (one per line;\n"
+      "                         : use \"-\" to read from standard input)\n"
+      "  --config-dir ARG       : use ARG to override the config directory\n"
+      "  --config-option ARG    : use ARG to override a configuration option\n"
+      "  --no-auth-cache        : do not cache authentication tokens\n"
+      "  --version              : print version information\n"),
+                  stream, pool));
   apr_pool_destroy(pool);
   exit(exit_val);
 }
@@ -959,6 +990,53 @@ display_version(apr_getopt_t *os, apr_po
   return SVN_NO_ERROR;
 }
 
+/* Return an error about the mutual exclusivity of the -m, -F, and
+   --with-revprop=svn:log command-line options. */
+static svn_error_t *
+mutually_exclusive_logs_error(void)
+{
+  return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                          _("--message (-m), --file (-F), and "
+                            "--with-revprop=svn:log are mutually "
+                            "exclusive"));
+}
+
+/* Ensure that the REVPROPS hash contains a command-line-provided log
+   message, if any, and that there was but one source of such a thing
+   provided on that command-line.  */
+static svn_error_t *
+sanitize_log_sources(apr_hash_t *revprops,
+                     const char *message,
+                     svn_stringbuf_t *filedata)
+{
+  apr_pool_t *hash_pool = apr_hash_pool_get(revprops);
+
+  /* If we already have a log message in the revprop hash, then just
+     make sure the user didn't try to also use -m or -F.  Otherwise,
+     we need to consult -m or -F to find a log message, if any. */
+  if (apr_hash_get(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING))
+    {
+      if (filedata || message)
+        return mutually_exclusive_logs_error();
+    }
+  else if (filedata)
+    {
+      if (message)
+        return mutually_exclusive_logs_error();
+
+      SVN_ERR(svn_utf_cstring_to_utf8(&message, filedata->data, hash_pool));
+      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
+                   svn_stringbuf__morph_into_string(filedata));
+    }
+  else if (message)
+    {
+      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
+                   svn_string_create(message, hash_pool));
+    }
+  
+  return SVN_NO_ERROR;
+}
+
 int
 main(int argc, const char **argv)
 {
@@ -994,6 +1072,7 @@ main(int argc, const char **argv)
     {NULL, 0, 0, NULL}
   };
   const char *message = NULL;
+  svn_stringbuf_t *filedata = NULL;
   const char *username = NULL, *password = NULL;
   const char *root_url = NULL, *extra_args_file = NULL;
   const char *config_dir = NULL;
@@ -1031,12 +1110,9 @@ main(int argc, const char **argv)
         case 'F':
           {
             const char *arg_utf8;
-            svn_stringbuf_t *contents;
             err = svn_utf_cstring_to_utf8(&arg_utf8, arg, pool);
             if (! err)
-              err = svn_stringbuf_from_file2(&contents, arg, pool);
-            if (! err)
-              err = svn_utf_cstring_to_utf8(&message, contents->data, pool);
+              err = svn_stringbuf_from_file2(&filedata, arg, pool);
             if (err)
               handle_error(err, pool);
           }
@@ -1109,6 +1185,11 @@ main(int argc, const char **argv)
         }
     }
 
+  /* Make sure we have a log message to use. */
+  err = sanitize_log_sources(revprops, message, filedata);
+  if (err)
+    handle_error(err, pool);
+
   /* Copy the rest of our command-line arguments to an array,
      UTF-8-ing them along the way. */
   action_args = apr_array_make(pool, opts->argc, sizeof(const char *));
@@ -1324,21 +1405,6 @@ main(int argc, const char **argv)
   if (! actions->nelts)
     usage(pool, EXIT_FAILURE);
 
-  if (message == NULL)
-    {
-      if (apr_hash_get(revprops, SVN_PROP_REVISION_LOG,
-                       APR_HASH_KEY_STRING) == NULL)
-        /* None of -F, -m, or --with-revprop=svn:log specified; default. */
-        apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
-                     svn_string_create("committed using svnmucc", pool));
-    }
-  else
-    {
-      /* -F or -m specified; use that even if --with-revprop=svn:log. */
-      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
-                   svn_string_create(message, pool));
-    }
-
   if ((err = execute(actions, anchor, revprops, username, password,
                      config_dir, config_options, non_interactive,
                      no_auth_cache, base_revision, pool)))

Modified: subversion/branches/javahl-ra/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnrdump/dump_editor.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/javahl-ra/subversion/svnrdump/dump_editor.c Fri Dec 28 23:03:51 2012
@@ -50,7 +50,8 @@ struct dir_baton
   struct dump_edit_baton *eb;
   struct dir_baton *parent_dir_baton;
 
-  apr_pool_t *pool; /* Directory pool */
+  /* Pool for per-directory allocations */
+  apr_pool_t *pool;
 
   /* is this directory a new addition to this revision? */
   svn_boolean_t added;
@@ -65,11 +66,21 @@ struct dir_baton
   const char *copyfrom_path; /* a relpath */
   svn_revnum_t copyfrom_rev;
 
+  /* Properties which were modified during change_dir_prop. */
+  apr_hash_t *props;
+
+  /* Properties which were deleted during change_dir_prop. */
+  apr_hash_t *deleted_props;
+
   /* Hash of paths that need to be deleted, though some -might- be
      replaced.  Maps const char * paths to this dir_baton. Note that
      they're full paths, because that's what the editor driver gives
      us, although they're all really within this directory. */
   apr_hash_t *deleted_entries;
+
+  /* Flags to trigger dumping props and record termination newlines. */
+  svn_boolean_t dump_props;
+  svn_boolean_t dump_newlines;
 };
 
 /* A file baton used by all file-related callback functions in the dump
@@ -79,11 +90,32 @@ struct file_baton
   struct dump_edit_baton *eb;
   struct dir_baton *parent_dir_baton;
 
+  /* Pool for per-file allocations */
+  apr_pool_t *pool;
+
   /* the path to this file */
   const char *repos_relpath; /* a relpath */
 
+  /* Properties which were modified during change_file_prop. */
+  apr_hash_t *props;
+
+  /* Properties which were deleted during change_file_prop. */
+  apr_hash_t *deleted_props;
+
   /* The checksum of the file the delta is being applied to */
   const char *base_checksum;
+
+  /* Copy state and source information (if any). */
+  svn_boolean_t is_copy;
+  const char *copyfrom_path;
+  svn_revnum_t copyfrom_rev;
+
+  /* The action associate with this node. */
+  enum svn_node_action action;
+  
+  /* Flags to trigger dumping props and text. */
+  svn_boolean_t dump_text;
+  svn_boolean_t dump_props;
 };
 
 /* A handler baton to be used in window_handler().  */
@@ -112,31 +144,20 @@ struct dump_edit_baton {
   /* Pool for per-revision allocations */
   apr_pool_t *pool;
 
-  /* Properties which were modified during change_file_prop
-   * or change_dir_prop. */
-  apr_hash_t *props;
-
-  /* Properties which were deleted during change_file_prop
-   * or change_dir_prop. */
-  apr_hash_t *deleted_props;
-
-  /* Temporary buffer to write property hashes to in human-readable
-   * form. ### Is this really needed? */
-  svn_stringbuf_t *propstring;
-
   /* Temporary file used for textdelta application along with its
      absolute path; these two variables should be allocated in the
      per-edit-session pool */
   const char *delta_abspath;
   apr_file_t *delta_file;
 
-  /* Flags to trigger dumping props and text */
-  svn_boolean_t dump_text;
-  svn_boolean_t dump_props;
-  svn_boolean_t dump_newlines;
-
   /* The revision we're currently dumping. */
   svn_revnum_t current_revision;
+
+  /* The kind (file or directory) and baton of the item whose block of
+     dump stream data has not been fully completed; NULL if there's no
+     such item. */
+  svn_node_kind_t pending_kind;
+  void *pending_baton;
 };
 
 /* Make a directory baton to represent the directory at PATH (relative
@@ -147,21 +168,20 @@ struct dump_edit_baton {
  * information is valid, the directory will be compared against its
  * copy source.
  *
- * PARENT_DIR_BATON is the directory baton of this directory's parent,
- * or NULL if this is the top-level directory of the edit.  ADDED
- * indicates if this directory is newly added in this revision.
- * Perform all allocations in POOL.  */
+ * PB is the directory baton of this directory's parent, or NULL if
+ * this is the top-level directory of the edit.  ADDED indicates if
+ * this directory is newly added in this revision.  Perform all
+ * allocations in POOL.  */
 static struct dir_baton *
 make_dir_baton(const char *path,
                const char *copyfrom_path,
                svn_revnum_t copyfrom_rev,
                void *edit_baton,
-               void *parent_dir_baton,
+               struct dir_baton *pb,
                svn_boolean_t added,
                apr_pool_t *pool)
 {
   struct dump_edit_baton *eb = edit_baton;
-  struct dir_baton *pb = parent_dir_baton;
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
   const char *repos_relpath;
 
@@ -186,11 +206,38 @@ make_dir_baton(const char *path,
   new_db->copyfrom_rev = copyfrom_rev;
   new_db->added = added;
   new_db->written_out = FALSE;
+  new_db->props = apr_hash_make(pool);
+  new_db->deleted_props = apr_hash_make(pool);
   new_db->deleted_entries = apr_hash_make(pool);
 
   return new_db;
 }
 
+/* Make a file baton to represent the directory at PATH (relative to
+ * PB->eb).  PB is the directory baton of this directory's parent, or
+ * NULL if this is the top-level directory of the edit.  Perform all
+ * allocations in POOL.  */
+static struct file_baton *
+make_file_baton(const char *path,
+                struct dir_baton *pb,
+                apr_pool_t *pool)
+{
+  struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
+
+  new_fb->eb = pb->eb;
+  new_fb->parent_dir_baton = pb;
+  new_fb->pool = pool;
+  new_fb->repos_relpath = svn_relpath_canonicalize(path, pool);
+  new_fb->props = apr_hash_make(pool);
+  new_fb->deleted_props = apr_hash_make(pool);
+  new_fb->is_copy = FALSE;
+  new_fb->copyfrom_path = NULL;
+  new_fb->copyfrom_rev = SVN_INVALID_REVNUM;
+  new_fb->action = svn_node_action_change;
+
+  return new_fb;
+}
+
 /* Return in *HEADER and *CONTENT the headers and content for PROPS. */
 static svn_error_t *
 get_props_content(svn_stringbuf_t **header,
@@ -227,9 +274,13 @@ get_props_content(svn_stringbuf_t **head
   return SVN_NO_ERROR;
 }
 
-/* Extract and dump properties stored in edit baton EB, using POOL for
- * any temporary allocations. If TRIGGER_VAR is not NULL, it is set to FALSE.
- * Unless DUMP_DATA_TOO is set, only property headers are dumped.
+/* Extract and dump properties stored in PROPS and property deletions
+ * stored in DELETED_PROPS. If TRIGGER_VAR is not NULL, it is set to
+ * FALSE.
+ *
+ * If PROPSTRING is non-NULL, set *PROPSTRING to a string containing
+ * the content block of the property changes; otherwise, dump that to
+ * the stream, too.
  */
 static svn_error_t *
 do_dump_props(svn_stringbuf_t **propstring,
@@ -237,7 +288,6 @@ do_dump_props(svn_stringbuf_t **propstri
               apr_hash_t *props,
               apr_hash_t *deleted_props,
               svn_boolean_t *trigger_var,
-              svn_boolean_t dump_data_too,
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
@@ -250,14 +300,14 @@ do_dump_props(svn_stringbuf_t **propstri
 
   SVN_ERR(get_props_content(&header, &content, props, deleted_props,
                             result_pool, scratch_pool));
-
-  /* This is a wacky side-effect of this function. */
-  *propstring = content;
-
   len = header->len;
   SVN_ERR(svn_stream_write(stream, header->data, &len));
 
-  if (dump_data_too)
+  if (propstring)
+    {
+      *propstring = content;
+    }
+  else
     {
       /* Content-length: 14 */
       SVN_ERR(svn_stream_printf(stream, scratch_pool,
@@ -309,7 +359,8 @@ do_dump_newlines(struct dump_edit_baton 
 static svn_error_t *
 dump_node(struct dump_edit_baton *eb,
           const char *repos_relpath,
-          svn_node_kind_t kind,
+          struct dir_baton *db,
+          struct file_baton *fb,
           enum svn_node_action action,
           svn_boolean_t is_copy,
           const char *copyfrom_path,
@@ -320,20 +371,23 @@ dump_node(struct dump_edit_baton *eb,
 
   assert(svn_relpath_is_canonical(repos_relpath));
   assert(!copyfrom_path || svn_relpath_is_canonical(copyfrom_path));
+  assert(! (db && fb));
 
   /* Add the edit root relpath prefix if necessary. */
   if (eb->update_anchor_relpath)
-    node_relpath = svn_relpath_join(eb->update_anchor_relpath, node_relpath, pool);
+    node_relpath = svn_relpath_join(eb->update_anchor_relpath,
+                                    node_relpath, pool);
 
-  /* Node-path: commons/STATUS */
+  /* Node-path: ... */
   SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n", node_relpath));
+                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
+                            node_relpath));
 
-  /* Node-kind: file */
-  if (kind == svn_node_file)
+  /* Node-kind: "file" | "dir" */
+  if (fb)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
-  else if (kind == svn_node_dir)
+  else if (db)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
 
@@ -344,13 +398,24 @@ dump_node(struct dump_edit_baton *eb,
     case svn_node_action_change:
       /* We are here after a change_file_prop or change_dir_prop. They
          set up whatever dump_props they needed to- nothing to
-         do here but print node action information */
+         do here but print node action information.
+
+         Node-action: change.  */
       SVN_ERR(svn_stream_puts(eb->stream,
                               SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
       break;
 
     case svn_node_action_replace:
-      if (!is_copy)
+      if (is_copy)
+        {
+          /* Delete the original, and then re-add the replacement as a
+             copy using recursive calls into this function. */
+          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_delete,
+                            FALSE, NULL, SVN_INVALID_REVNUM, pool));
+          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_add,
+                            is_copy, copyfrom_path, copyfrom_rev, pool));
+        }
+      else
         {
           /* Node-action: replace */
           SVN_ERR(svn_stream_puts(eb->stream,
@@ -359,25 +424,15 @@ dump_node(struct dump_edit_baton *eb,
 
           /* Wait for a change_*_prop to be called before dumping
              anything */
-          eb->dump_props = TRUE;
-          break;
+          if (fb)
+            fb->dump_props = TRUE;
+          else if (db)
+            db->dump_props = TRUE;
         }
-      /* More complex case: is_copy is true, and copyfrom_path/
-         copyfrom_rev are present: delete the original, and then re-add
-         it */
-
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n\n"));
-
-      /* Recurse: Print an additional add-with-history record. */
-      SVN_ERR(dump_node(eb, repos_relpath, kind, svn_node_action_add,
-                        is_copy, copyfrom_path, copyfrom_rev, pool));
-
-      /* We can leave this routine quietly now, don't need to dump any
-         content; that was already done in the second record. */
       break;
 
     case svn_node_action_delete:
+      /* Node-action: delete */
       SVN_ERR(svn_stream_puts(eb->stream,
                               SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
 
@@ -385,44 +440,57 @@ dump_node(struct dump_edit_baton *eb,
          print a couple of newlines because we're not dumping props or
          text. */
       SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
+
       break;
 
     case svn_node_action_add:
+      /* Node-action: add */
       SVN_ERR(svn_stream_puts(eb->stream,
                               SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
 
-      if (!is_copy)
+      if (is_copy)
         {
-          /* eb->dump_props for files is handled in close_file
-             which is called immediately.  However, directories are not
-             closed until all the work inside them has been done;
-             eb->dump_props for directories is handled in all the
-             functions that can possibly be called after add_directory:
-             add_directory, open_directory, delete_entry, close_directory,
-             add_file, open_file. change_dir_prop is a special case. */
-
-          /* Wait for a change_*_prop to be called before dumping
-             anything */
-          eb->dump_props = TRUE;
-          break;
+          /* Node-copyfrom-rev / Node-copyfrom-path */
+          SVN_ERR(svn_stream_printf(eb->stream, pool,
+                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
+                                    ": %ld\n"
+                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
+                                    ": %s\n",
+                                    copyfrom_rev, copyfrom_path));
+
+          /* Ugly hack: If a directory was copied from a previous
+             revision, nothing like close_file() will be called to write two
+             blank lines. If change_dir_prop() is called, props are dumped
+             (along with the necessary PROPS-END\n\n and we're good. So
+             set DUMP_NEWLINES here to print the newlines unless
+             change_dir_prop() is called next otherwise the `svnadmin load`
+             parser will fail.  */
+          if (db)
+            db->dump_newlines = TRUE;
         }
+      else
+        {
+          /* fb->dump_props (for files) is handled in close_file()
+             which is called immediately.
 
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
-                                ": %ld\n"
-                                SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
-                                ": %s\n",
-                                copyfrom_rev, copyfrom_path));
-
-      /* Ugly hack: If a directory was copied from a previous
-         revision, nothing like close_file() will be called to write two
-         blank lines. If change_dir_prop() is called, props are dumped
-         (along with the necessary PROPS-END\n\n and we're good. So
-         set DUMP_NEWLINES here to print the newlines unless
-         change_dir_prop() is called next otherwise the `svnadmin load`
-         parser will fail.  */
-      if (kind == svn_node_dir)
-        eb->dump_newlines = TRUE;
+             However, directories are not closed until all the work
+             inside them has been done; db->dump_props (for directories)
+             is handled (via dump_pending()) in all the functions that
+             can possibly be called after add_directory():
+
+               - add_directory()
+               - open_directory()
+               - delete_entry()
+               - close_directory()
+               - add_file()
+               - open_file()
+
+             change_dir_prop() is a special case. */
+          if (fb)
+            fb->dump_props = TRUE;
+          else if (db)
+            db->dump_props = TRUE;
+        }
 
       break;
     }
@@ -440,7 +508,8 @@ dump_mkdir(struct dump_edit_baton *eb,
 
   /* Node-path: ... */
   SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n", repos_relpath));
+                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
+                            repos_relpath));
 
   /* Node-kind: dir */
   SVN_ERR(svn_stream_printf(eb->stream, pool,
@@ -472,21 +541,45 @@ dump_mkdir(struct dump_edit_baton *eb,
 /* Dump pending items from the specified node, to allow starting the dump
    of a child node */
 static svn_error_t *
-dump_pending(struct dir_baton *pb,
+dump_pending(struct dump_edit_baton *eb,
              apr_pool_t *scratch_pool)
 {
-  /* Some pending properties to dump? */
-  SVN_ERR(do_dump_props(&pb->eb->propstring, pb->eb->stream,
-                        pb->eb->props, pb->eb->deleted_props,
-                        &(pb->eb->dump_props), TRUE,
-                        pb->pool, scratch_pool));
+  if (! eb->pending_baton)
+    return SVN_NO_ERROR;
+
+  if (eb->pending_kind == svn_node_dir)
+    {
+      struct dir_baton *db = eb->pending_baton;
+
+      /* Some pending properties to dump? */
+      SVN_ERR(do_dump_props(NULL, eb->stream, db->props, db->deleted_props,
+                            &(db->dump_props), db->pool, scratch_pool));
+      
+      /* Some pending newlines to dump? */
+      SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
+    }
+  else if (eb->pending_kind == svn_node_file)
+    {
+      struct file_baton *fb = eb->pending_baton;
 
-  /* Some pending newlines to dump? */
-  SVN_ERR(do_dump_newlines(pb->eb, &(pb->eb->dump_newlines), scratch_pool));
+      /* Some pending properties to dump? */
+      SVN_ERR(do_dump_props(NULL, eb->stream, fb->props, fb->deleted_props,
+                            &(fb->dump_props), fb->pool, scratch_pool));
+    }
+  else
+    abort();
+
+  /* Anything that was pending is pending no longer. */
+  eb->pending_baton = NULL;
+  eb->pending_kind = svn_node_none;
 
   return SVN_NO_ERROR;
 }
 
+
+
+/*** Editor Function Implementations ***/
+
 static svn_error_t *
 open_root(void *edit_baton,
           svn_revnum_t base_revision,
@@ -499,10 +592,6 @@ open_root(void *edit_baton,
   /* Clear the per-revision pool after each revision */
   svn_pool_clear(eb->pool);
 
-  eb->props = apr_hash_make(eb->pool);
-  eb->deleted_props = apr_hash_make(eb->pool);
-  eb->propstring = svn_stringbuf_create_empty(eb->pool);
-
   LDR_DBG(("open_root %p\n", *root_baton));
 
   if (eb->update_anchor_relpath)
@@ -538,10 +627,15 @@ open_root(void *edit_baton,
                  to letting the typical plumbing handle this task. */
               new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
                                       edit_baton, NULL, TRUE, pool);
-              SVN_ERR(dump_node(eb, new_db->repos_relpath, svn_node_dir,
-                                svn_node_action_add, FALSE, NULL, SVN_INVALID_REVNUM,
-                                pool));
+              SVN_ERR(dump_node(eb, new_db->repos_relpath, new_db,
+                                NULL, svn_node_action_add, FALSE,
+                                NULL, SVN_INVALID_REVNUM, pool));
+
+              /* Remember that we've started but not yet finished
+                 handling this directory. */
               new_db->written_out = TRUE;
+              eb->pending_baton = new_db;
+              eb->pending_kind = svn_node_dir;
             }
         }
       svn_pool_destroy(iterpool);
@@ -554,7 +648,6 @@ open_root(void *edit_baton,
     }
 
   *root_baton = new_db;
-    
   return SVN_NO_ERROR;
 }
 
@@ -568,10 +661,12 @@ delete_entry(const char *path,
 
   LDR_DBG(("delete_entry %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
 
-  /* Add this path to the deleted_entries of the parent directory
-     baton. */
+  /* We don't dump this deletion immediate.  Rather, we add this path
+     to the deleted_entries of the parent directory baton.  That way,
+     we can tell (later) an addition from a replacement.  All the real
+     deletions get handled in close_directory().  */
   apr_hash_set(pb->deleted_entries, apr_pstrdup(pb->eb->pool, path),
                APR_HASH_KEY_STRING, pb);
 
@@ -593,11 +688,11 @@ add_directory(const char *path,
 
   LDR_DBG(("add_directory %s\n", path));
 
+  SVN_ERR(dump_pending(pb->eb, pool));
+
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
                           pb, TRUE, pb->eb->pool);
 
-  SVN_ERR(dump_pending(pb, pool));
-
   /* This might be a replacement -- is the path already deleted? */
   val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
 
@@ -605,8 +700,7 @@ add_directory(const char *path,
   is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
 
   /* Dump the node */
-  SVN_ERR(dump_node(pb->eb, new_db->repos_relpath,
-                    svn_node_dir,
+  SVN_ERR(dump_node(pb->eb, new_db->repos_relpath, new_db, NULL,
                     val ? svn_node_action_replace : svn_node_action_add,
                     is_copy,
                     is_copy ? new_db->copyfrom_path : NULL,
@@ -617,7 +711,11 @@ add_directory(const char *path,
     /* Delete the path, it's now been dumped */
     apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
 
+  /* Remember that we've started, but not yet finished handling this
+     directory. */
   new_db->written_out = TRUE;
+  pb->eb->pending_baton = new_db;
+  pb->eb->pending_kind = svn_node_dir;
 
   *child_baton = new_db;
   return SVN_NO_ERROR;
@@ -637,7 +735,7 @@ open_directory(const char *path,
 
   LDR_DBG(("open_directory %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
 
   /* If the parent directory has explicit comparison path and rev,
      record the same for this one. */
@@ -651,6 +749,7 @@ open_directory(const char *path,
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
                           FALSE, pb->eb->pool);
+
   *child_baton = new_db;
   return SVN_NO_ERROR;
 }
@@ -661,10 +760,33 @@ close_directory(void *dir_baton,
 {
   struct dir_baton *db = dir_baton;
   apr_hash_index_t *hi;
+  svn_boolean_t this_pending;
 
   LDR_DBG(("close_directory %p\n", dir_baton));
 
-  SVN_ERR(dump_pending(db, pool));
+  /* Remember if this directory is the one currently pending. */
+  this_pending = (db->eb->pending_baton == db);
+
+  SVN_ERR(dump_pending(db->eb, pool));
+
+  /* If this directory was pending, then dump_pending() should have
+     taken care of all the props and such.  Of course, the only way
+     that would be the case is if this directory was added/replaced.
+
+     Otherwise, if stuff for this directory has already been written
+     out (at some point in the past, prior to our handling other
+     nodes), we might need to generate a second "change" record just
+     to carry the information we've since learned about the
+     directory. */ 
+  if ((! this_pending) && (db->dump_props))
+    {
+      SVN_ERR(dump_node(db->eb, db->repos_relpath, db, NULL,
+                        svn_node_action_change, FALSE,
+                        NULL, SVN_INVALID_REVNUM, pool));
+      db->eb->pending_baton = db;
+      db->eb->pending_kind = svn_node_dir;
+      SVN_ERR(dump_pending(db->eb, pool));
+    }
 
   /* Dump the deleted directory entries */
   for (hi = apr_hash_first(pool, db->deleted_entries); hi;
@@ -672,11 +794,13 @@ close_directory(void *dir_baton,
     {
       const char *path = svn__apr_hash_index_key(hi);
 
-      SVN_ERR(dump_node(db->eb, path, svn_node_unknown, svn_node_action_delete,
+      SVN_ERR(dump_node(db->eb, path, NULL, NULL, svn_node_action_delete,
                         FALSE, NULL, SVN_INVALID_REVNUM, pool));
     }
 
+  /* ### should be unnecessary */
   SVN_ERR(svn_hash__clear(db->deleted_entries, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -689,42 +813,33 @@ add_file(const char *path,
          void **file_baton)
 {
   struct dir_baton *pb = parent_baton;
-  struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
+  struct file_baton *fb;
   void *val;
-  svn_boolean_t is_copy;
-
-  fb->eb = pb->eb;
-  fb->parent_dir_baton = pb;
-  fb->repos_relpath = svn_relpath_canonicalize(path, pool);
 
   LDR_DBG(("add_file %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
 
+  /* Make the file baton. */
+  fb = make_file_baton(path, pb, pool);
+  
   /* This might be a replacement -- is the path already deleted? */
   val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
 
   /* Detect add-with-history. */
-  is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
-
-  /* Dump the node. */
-  SVN_ERR(dump_node(pb->eb, fb->repos_relpath,
-                    svn_node_file,
-                    val ? svn_node_action_replace : svn_node_action_add,
-                    is_copy,
-                    is_copy ? svn_relpath_canonicalize(copyfrom_path, pool)
-                            : NULL,
-                    is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
-                    pool));
+  if (ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev))
+    {    
+      fb->copyfrom_path = svn_relpath_canonicalize(copyfrom_path, fb->pool);
+      fb->copyfrom_rev = copyfrom_rev;
+      fb->is_copy = TRUE;
+    }
+  fb->action = val ? svn_node_action_replace : svn_node_action_add;
 
+  /* Delete the path, it's now been dumped. */
   if (val)
-    /* delete the path, it's now been dumped. */
     apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
 
-  /* Build a nice file baton to pass to change_file_prop and
-     apply_textdelta */
   *file_baton = fb;
-
   return SVN_NO_ERROR;
 }
 
@@ -736,36 +851,26 @@ open_file(const char *path,
           void **file_baton)
 {
   struct dir_baton *pb = parent_baton;
-  struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
-  const char *copyfrom_path = NULL;
-  svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
-
-  fb->eb = pb->eb;
-  fb->parent_dir_baton = pb;
-  fb->repos_relpath = svn_relpath_canonicalize(path, pool);
+  struct file_baton *fb;
 
   LDR_DBG(("open_file %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
+
+  /* Make the file baton. */
+  fb = make_file_baton(path, pb, pool);
 
   /* If the parent directory has explicit copyfrom path and rev,
      record the same for this one. */
   if (ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev))
     {
-      copyfrom_path = svn_relpath_join(pb->copyfrom_path,
-                                       svn_relpath_basename(path, NULL),
-                                       pb->eb->pool);
-      copyfrom_rev = pb->copyfrom_rev;
+      fb->copyfrom_path = svn_relpath_join(pb->copyfrom_path,
+                                           svn_relpath_basename(path, NULL),
+                                           pb->eb->pool);
+      fb->copyfrom_rev = pb->copyfrom_rev;
     }
 
-  SVN_ERR(dump_node(pb->eb, fb->repos_relpath, svn_node_file,
-                    svn_node_action_change, FALSE, copyfrom_path,
-                    copyfrom_rev, pool));
-
-  /* Build a nice file baton to pass to change_file_prop and
-     apply_textdelta */
   *file_baton = fb;
-
   return SVN_NO_ERROR;
 }
 
@@ -776,37 +881,30 @@ change_dir_prop(void *parent_baton,
                 apr_pool_t *pool)
 {
   struct dir_baton *db = parent_baton;
-
+  svn_boolean_t this_pending;
+  
   LDR_DBG(("change_dir_prop %p\n", parent_baton));
 
+  /* This directory is not pending, but something else is, so handle
+     the "something else".  */
+  this_pending = (db->eb->pending_baton == db);
+  if (! this_pending)
+    SVN_ERR(dump_pending(db->eb, pool));
+
   if (svn_property_kind2(name) != svn_prop_regular_kind)
     return SVN_NO_ERROR;
 
   if (value)
-    apr_hash_set(db->eb->props, apr_pstrdup(db->eb->pool, name),
-                 APR_HASH_KEY_STRING, svn_string_dup(value, db->eb->pool));
+    apr_hash_set(db->props, apr_pstrdup(db->pool, name),
+                 APR_HASH_KEY_STRING, svn_string_dup(value, db->pool));
   else
-    apr_hash_set(db->eb->deleted_props, apr_pstrdup(db->eb->pool, name),
+    apr_hash_set(db->deleted_props, apr_pstrdup(db->pool, name),
                  APR_HASH_KEY_STRING, "");
 
-  if (! db->written_out)
-    {
-      /* If db->written_out is set, it means that the node information
-         corresponding to this directory has already been written: don't
-         do anything; do_dump_props() will take care of dumping the
-         props. If it not, dump the node itself before dumping the
-         props. */
-
-      SVN_ERR(dump_node(db->eb, db->repos_relpath, svn_node_dir,
-                        svn_node_action_change, FALSE, db->copyfrom_path,
-                        db->copyfrom_rev, pool));
-      db->written_out = TRUE;
-    }
-
   /* Make sure we eventually output the props, and disable printing
      a couple of extra newlines */
-  db->eb->dump_newlines = FALSE;
-  db->eb->dump_props = TRUE;
+  db->dump_newlines = FALSE;
+  db->dump_props = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -818,7 +916,6 @@ change_file_prop(void *file_baton,
                  apr_pool_t *pool)
 {
   struct file_baton *fb = file_baton;
-  struct dump_edit_baton *eb = fb->eb;
 
   LDR_DBG(("change_file_prop %p\n", file_baton));
 
@@ -826,16 +923,16 @@ change_file_prop(void *file_baton,
     return SVN_NO_ERROR;
 
   if (value)
-    apr_hash_set(eb->props, apr_pstrdup(eb->pool, name),
-                 APR_HASH_KEY_STRING, svn_string_dup(value, eb->pool));
+    apr_hash_set(fb->props, apr_pstrdup(fb->pool, name),
+                 APR_HASH_KEY_STRING, svn_string_dup(value, fb->pool));
   else
-    apr_hash_set(eb->deleted_props, apr_pstrdup(eb->pool, name),
+    apr_hash_set(fb->deleted_props, apr_pstrdup(fb->pool, name),
                  APR_HASH_KEY_STRING, "");
 
   /* Dump the property headers and wait; close_file might need
      to write text headers too depending on whether
      apply_textdelta is called */
-  eb->dump_props = TRUE;
+  fb->dump_props = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -864,15 +961,14 @@ apply_textdelta(void *file_baton, const 
 {
   struct file_baton *fb = file_baton;
   struct dump_edit_baton *eb = fb->eb;
-
-  /* Custom handler_baton allocated in a separate pool */
   struct handler_baton *hb;
   svn_stream_t *delta_filestream;
 
-  hb = apr_pcalloc(eb->pool, sizeof(*hb));
-
   LDR_DBG(("apply_textdelta %p\n", file_baton));
 
+  /* This is custom handler_baton, allocated from a separate pool.  */
+  hb = apr_pcalloc(eb->pool, sizeof(*hb));
+
   /* Use a temporary file to measure the Text-content-length */
   delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
 
@@ -881,7 +977,8 @@ apply_textdelta(void *file_baton, const 
                           delta_filestream, 0,
                           SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
 
-  eb->dump_text = TRUE;
+  /* Record that there's text to be dumped, and its base checksum. */
+  fb->dump_text = TRUE;
   fb->base_checksum = apr_pstrdup(eb->pool, base_checksum);
 
   /* The actual writing takes place when this function has
@@ -901,17 +998,25 @@ close_file(void *file_baton,
   struct file_baton *fb = file_baton;
   struct dump_edit_baton *eb = fb->eb;
   apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
-
+  svn_stringbuf_t *propstring;
+  
   LDR_DBG(("close_file %p\n", file_baton));
 
-  /* Some pending properties to dump? Dump just the headers- dump the
-     props only after dumping the text headers too (if present) */
-  SVN_ERR(do_dump_props(&eb->propstring, eb->stream,
-                        eb->props, eb->deleted_props,
-                        &(eb->dump_props), FALSE, pool, pool));
+  SVN_ERR(dump_pending(eb, pool));
+
+  /* Dump the node. */
+  SVN_ERR(dump_node(eb, fb->repos_relpath, NULL, fb,
+                    fb->action, fb->is_copy, fb->copyfrom_path,
+                    fb->copyfrom_rev, pool));
+
+  /* Some pending properties to dump?  We'll dump just the headers for
+     now, then dump the actual propchange content only after dumping
+     the text headers too (if present). */
+  SVN_ERR(do_dump_props(&propstring, eb->stream, fb->props, fb->deleted_props,
+                        &(fb->dump_props), pool, pool));
 
   /* Dump the text headers */
-  if (eb->dump_text)
+  if (fb->dump_text)
     {
       apr_status_t err;
 
@@ -946,31 +1051,31 @@ close_file(void *file_baton,
 
   /* Content-length: 1549 */
   /* If both text and props are absent, skip this header */
-  if (eb->dump_props)
+  if (fb->dump_props)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                               ": %ld\n\n",
-                              (unsigned long)info->size + eb->propstring->len));
-  else if (eb->dump_text)
+                              (unsigned long)info->size + propstring->len));
+  else if (fb->dump_text)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                               ": %ld\n\n",
                               (unsigned long)info->size));
 
   /* Dump the props now */
-  if (eb->dump_props)
+  if (fb->dump_props)
     {
-      SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
-                               &(eb->propstring->len)));
+      SVN_ERR(svn_stream_write(eb->stream, propstring->data,
+                               &(propstring->len)));
 
       /* Cleanup */
-      eb->dump_props = FALSE;
-      SVN_ERR(svn_hash__clear(eb->props, eb->pool));
-      SVN_ERR(svn_hash__clear(eb->deleted_props, eb->pool));
+      fb->dump_props = FALSE;
+      SVN_ERR(svn_hash__clear(fb->props, fb->pool));
+      SVN_ERR(svn_hash__clear(fb->deleted_props, fb->pool));
     }
 
   /* Dump the text */
-  if (eb->dump_text)
+  if (fb->dump_text)
     {
       /* Seek to the beginning of the delta file, map it to a stream,
          and copy the stream to eb->stream. Then close the stream and
@@ -987,7 +1092,6 @@ close_file(void *file_baton,
       /* Cleanup */
       SVN_ERR(svn_stream_close(delta_filestream));
       SVN_ERR(svn_io_file_trunc(eb->delta_file, 0, pool));
-      eb->dump_text = FALSE;
     }
 
   /* Write a couple of blank lines for matching output with `svnadmin
@@ -1132,6 +1236,7 @@ svn_rdump__get_dump_editor(const svn_del
   eb->ra_session = ra_session;
   eb->update_anchor_relpath = update_anchor_relpath;
   eb->current_revision = revision;
+  eb->pending_kind = svn_node_none;
 
   /* Create a special per-revision pool */
   eb->pool = svn_pool_create(pool);

Modified: subversion/branches/javahl-ra/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnrdump/load_editor.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/javahl-ra/subversion/svnrdump/load_editor.c Fri Dec 28 23:03:51 2012
@@ -501,7 +501,8 @@ get_shim_callbacks(struct revision_baton
 
 /* Acquire a lock (of sorts) on the repository associated with the
  * given RA SESSION. This lock is just a revprop change attempt in a
- * time-delay loop. This function is duplicated by svnsync in main.c.
+ * time-delay loop. This function is duplicated by svnsync in
+ * svnsync/svnsync.c
  *
  * ### TODO: Make this function more generic and
  * expose it through a header for use by other Subversion
@@ -855,6 +856,8 @@ set_revision_property(void *baton,
 {
   struct revision_baton *rb = baton;
 
+  SVN_ERR(svn_rdump__normalize_prop(name, &value, rb->pool));
+  
   SVN_ERR(svn_repos__validate_prop(name, value, rb->pool));
 
   if (rb->rev > 0)
@@ -934,6 +937,8 @@ set_node_property(void *baton,
         }
     }
 
+  SVN_ERR(svn_rdump__normalize_prop(name, &value, pool));
+
   SVN_ERR(svn_repos__validate_prop(name, value, pool));
 
   switch (nb->kind)

Modified: subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.c Fri Dec 28 23:03:51 2012
@@ -80,6 +80,7 @@ enum svn_svnrdump__longopt_t
     opt_auth_password,
     opt_auth_nocache,
     opt_non_interactive,
+    opt_force_interactive,
     opt_incremental,
     opt_trust_server_cert,
     opt_version
@@ -91,7 +92,8 @@ enum svn_svnrdump__longopt_t
                                    opt_auth_password, \
                                    opt_auth_nocache, \
                                    opt_trust_server_cert, \
-                                   opt_non_interactive
+                                   opt_non_interactive, \
+                                   opt_force_interactive
 
 static const svn_opt_subcommand_desc2_t svnrdump__cmd_table[] =
 {
@@ -127,7 +129,13 @@ static const apr_getopt_option_t svnrdum
     {"password",      opt_auth_password, 1,
                       N_("specify a password ARG")},
     {"non-interactive", opt_non_interactive, 0,
-                      N_("do no interactive prompting")},
+                      N_("do no interactive prompting (default is to prompt\n"
+                         "                             "
+                         "only if standard input is a terminal device)")},
+    {"force-interactive", opt_force_interactive, 0,
+                      N_("do interactive prompting even if standard input\n"
+                         "                             "
+                         "is not a terminal device")},
     {"no-auth-cache", opt_auth_nocache, 0,
                       N_("do not cache authentication tokens")},
     {"help",          'h', 0,
@@ -839,6 +847,7 @@ main(int argc, const char **argv)
   svn_boolean_t no_auth_cache = FALSE;
   svn_boolean_t trust_server_cert = FALSE;
   svn_boolean_t non_interactive = FALSE;
+  svn_boolean_t force_interactive = FALSE;
   apr_array_header_t *config_options = NULL;
   apr_getopt_t *os;
   const char *first_arg;
@@ -957,6 +966,9 @@ main(int argc, const char **argv)
         case opt_non_interactive:
           non_interactive = TRUE;
           break;
+        case opt_force_interactive:
+          force_interactive = TRUE;
+          break;
         case opt_incremental:
           opt_baton->incremental = TRUE;
           break;
@@ -975,6 +987,19 @@ main(int argc, const char **argv)
         }
     }
 
+  /* The --non-interactive and --force-interactive options are mutually
+   * exclusive. */
+  if (non_interactive && force_interactive)
+    {
+      err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("--non-interactive and --force-interactive "
+                               "are mutually exclusive"));
+      return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+    }
+  else
+    non_interactive = !svn_cmdline__be_interactive(non_interactive,
+                                                   force_interactive);
+
   if (opt_baton->help)
     {
       subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,

Modified: subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.h?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.h (original)
+++ subversion/branches/javahl-ra/subversion/svnrdump/svnrdump.h Fri Dec 28 23:03:51 2012
@@ -106,6 +106,20 @@ svn_rdump__normalize_props(apr_hash_t **
                            apr_hash_t *props,
                            apr_pool_t *result_pool);
 
+/* Normalize the line ending style of a single property that "needs
+ * translation" (according to svn_prop_needs_translation(),
+ * currently all svn:* props) so that they contain only LF (\n) line endings.
+ * "\r" characters found mid-line are replaced with "\n".
+ * "\r\n" sequences are replaced with "\n"
+ *
+ * NAME is used to check that VALUE should be normalized, and if this is the
+ * case, VALUE is then normalized, allocated from RESULT_POOL
+ */
+svn_error_t *
+svn_rdump__normalize_prop(const char *name,
+                          const svn_string_t **value,
+                          apr_pool_t *result_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/javahl-ra/subversion/svnrdump/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnrdump/util.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnrdump/util.c (original)
+++ subversion/branches/javahl-ra/subversion/svnrdump/util.c Fri Dec 28 23:03:51 2012
@@ -31,6 +31,25 @@
 
 
 svn_error_t *
+svn_rdump__normalize_prop(const char *name,
+                          const svn_string_t **value,
+                          apr_pool_t *result_pool)
+{
+  if (svn_prop_needs_translation(name))
+    {
+      const char *cstring;
+
+      SVN_ERR(svn_subst_translate_cstring2((*value)->data, &cstring,
+                                           "\n", TRUE,
+                                           NULL, FALSE,
+                                           result_pool));
+
+      *value = svn_string_create(cstring, result_pool);
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_rdump__normalize_props(apr_hash_t **normal_props,
                            apr_hash_t *props,
                            apr_pool_t *result_pool)
@@ -45,16 +64,8 @@ svn_rdump__normalize_props(apr_hash_t **
       const char *key = svn__apr_hash_index_key(hi);
       const svn_string_t *value = svn__apr_hash_index_val(hi);
 
-      if (svn_prop_needs_translation(key))
-        {
-          const char *cstring;
-
-          SVN_ERR(svn_subst_translate_cstring2(value->data, &cstring,
-                                               "\n", TRUE,
-                                               NULL, FALSE,
-                                               result_pool));
-          value = svn_string_create(cstring, result_pool);
-        }
+      SVN_ERR(svn_rdump__normalize_prop(key, &value,
+                                        result_pool));
 
       apr_hash_set(*normal_props, key, APR_HASH_KEY_STRING, value);
     }

Modified: subversion/branches/javahl-ra/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnserve/serve.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnserve/serve.c (original)
+++ subversion/branches/javahl-ra/subversion/svnserve/serve.c Fri Dec 28 23:03:51 2012
@@ -221,37 +221,26 @@ static svn_error_t *log_command(server_b
   return log_write(b->log_file, line, nbytes, pool);
 }
 
-svn_error_t *load_configs(svn_config_t **cfg,
-                          svn_config_t **pwdb,
-                          svn_authz_t **authzdb,
-                          enum username_case_type *username_case,
-                          const char *filename,
-                          svn_boolean_t must_exist,
-                          const char *base,
-                          server_baton_t *server,
-                          svn_ra_svn_conn_t *conn,
-                          apr_pool_t *pool)
+svn_error_t *load_pwdb_config(server_baton_t *server,
+                              svn_ra_svn_conn_t *conn,
+                              apr_pool_t *pool)
 {
-  const char *pwdb_path, *authzdb_path;
+  const char *pwdb_path;
   svn_error_t *err;
 
-  SVN_ERR(svn_config_read2(cfg, filename, must_exist, FALSE, pool));
-
-  svn_config_get(*cfg, &pwdb_path, SVN_CONFIG_SECTION_GENERAL,
+  svn_config_get(server->cfg, &pwdb_path, SVN_CONFIG_SECTION_GENERAL,
                  SVN_CONFIG_OPTION_PASSWORD_DB, NULL);
 
-  *pwdb = NULL;
+  server->pwdb = NULL;
   if (pwdb_path)
     {
       pwdb_path = svn_dirent_canonicalize(pwdb_path, pool);
-      pwdb_path = svn_dirent_join(base, pwdb_path, pool);
+      pwdb_path = svn_dirent_join(server->base, pwdb_path, pool);
 
-      err = svn_config_read2(pwdb, pwdb_path, TRUE, FALSE, pool);
+      err = svn_config_read2(&server->pwdb, pwdb_path, TRUE, FALSE, pool);
       if (err)
         {
-          if (server)
-            /* Called by listening server; log error no matter what it is. */
-            log_server_error(err, server, conn, pool);
+          log_server_error(err, server, conn, pool);
 
           /* Because it may be possible to read the pwdb file with some
              access methods and not others, ignore errors reading the pwdb
@@ -265,18 +254,11 @@ svn_error_t *load_configs(svn_config_t *
           if (err->apr_err != SVN_ERR_BAD_FILENAME
               && ! APR_STATUS_IS_EACCES(err->apr_err))
             {
-              if (server)
-                {
-                  /* Called by listening server: Now that we've logged
-                   * the error, clear it and return a nice, generic
-                   * error to the user
-                   * (http://subversion.tigris.org/issues/show_bug.cgi?id=2271). */
-                  svn_error_clear(err);
-                  return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL, NULL);
-                }
-              /* Called during startup; return the error, whereupon it
-               * will go to standard error for the admin to see. */
-              return err;
+                /* Now that we've logged the error, clear it and return a
+                 * nice, generic error to the user:
+                 * http://subversion.tigris.org/issues/show_bug.cgi?id=2271 */
+                svn_error_clear(err);
+                return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL, NULL);
             }
           else
             /* Ignore SVN_ERR_BAD_FILENAME and APR_EACCES and proceed. */
@@ -284,51 +266,59 @@ svn_error_t *load_configs(svn_config_t *
         }
     }
 
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *load_authz_config(server_baton_t *server,
+                               svn_ra_svn_conn_t *conn,
+                               const char *repos_root,
+                               apr_pool_t *pool)
+{
+  const char *authzdb_path;
+  svn_error_t *err;
+
   /* Read authz configuration. */
-  svn_config_get(*cfg, &authzdb_path, SVN_CONFIG_SECTION_GENERAL,
+  svn_config_get(server->cfg, &authzdb_path, SVN_CONFIG_SECTION_GENERAL,
                  SVN_CONFIG_OPTION_AUTHZ_DB, NULL);
   if (authzdb_path)
     {
       const char *case_force_val;
 
-      authzdb_path = svn_dirent_canonicalize(authzdb_path, pool);
-      authzdb_path = svn_dirent_join(base, authzdb_path, pool);
-      err = svn_repos_authz_read(authzdb, authzdb_path, TRUE, pool);
+      if (!svn_path_is_repos_relative_url(authzdb_path) &&
+          !svn_path_is_url(authzdb_path))
+        {
+          /* Canonicalize and add the base onto authzdb_path (if needed)
+           * when authzdb_path is not a URL (repos relative or absolute). */
+          authzdb_path = svn_dirent_canonicalize(authzdb_path, pool);
+          authzdb_path = svn_dirent_join(server->base, authzdb_path, pool);
+        }
+      err = svn_repos_authz_read2(&server->authzdb, authzdb_path, TRUE,
+                                  repos_root, pool);
       if (err)
         {
-          if (server)
-            {
-              /* Called by listening server: Log the error, clear it,
-               * and return a nice, generic error to the user
-               * (http://subversion.tigris.org/issues/show_bug.cgi?id=2271). */
-              log_server_error(err, server, conn, pool);
-              svn_error_clear(err);
-              return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, NULL);
-            }
-          else
-            /* Called during startup; return the error, whereupon it
-             * will go to standard error for the admin to see. */
-            return err;
+          log_server_error(err, server, conn, pool);
+          svn_error_clear(err);
+          return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, NULL);
         }
 
       /* Are we going to be case-normalizing usernames when we consult
        * this authz file? */
-      svn_config_get(*cfg, &case_force_val, SVN_CONFIG_SECTION_GENERAL,
+      svn_config_get(server->cfg, &case_force_val, SVN_CONFIG_SECTION_GENERAL,
                      SVN_CONFIG_OPTION_FORCE_USERNAME_CASE, NULL);
       if (case_force_val)
         {
           if (strcmp(case_force_val, "upper") == 0)
-            *username_case = CASE_FORCE_UPPER;
+            server->username_case = CASE_FORCE_UPPER;
           else if (strcmp(case_force_val, "lower") == 0)
-            *username_case = CASE_FORCE_LOWER;
+            server->username_case = CASE_FORCE_LOWER;
           else
-            *username_case = CASE_ASIS;
+            server->username_case = CASE_ASIS;
         }
     }
   else
     {
-      *authzdb = NULL;
-      *username_case = CASE_ASIS;
+      server->authzdb = NULL;
+      server->username_case = CASE_ASIS;
     }
 
   return SVN_NO_ERROR;
@@ -3138,14 +3128,26 @@ static svn_error_t *find_repos(const cha
     b->repos_name = b->authz_repos_name;
   b->repos_name = svn_path_uri_encode(b->repos_name, pool);
 
-  /* If the svnserve configuration files have not been loaded then
-     load them from the repository. */
+  /* If the svnserve configuration has not been loaded then load it from the
+   * repository. */
   if (NULL == b->cfg)
-    SVN_ERR(load_configs(&b->cfg, &b->pwdb, &b->authzdb, &b->username_case,
-                         svn_repos_svnserve_conf(b->repos, pool), FALSE,
-                         svn_repos_conf_dir(b->repos, pool),
-                         b, conn,
-                         pool));
+    {
+      b->base = svn_repos_conf_dir(b->repos, pool);
+
+      SVN_ERR(svn_config_read2(&b->cfg, svn_repos_svnserve_conf(b->repos, pool),
+                               FALSE, /* must_exist */
+                               FALSE, /* section_names_case_sensitive */
+                               pool));
+      SVN_ERR(load_pwdb_config(b, conn, pool));
+      SVN_ERR(load_authz_config(b, conn, repos_root, pool));
+    }
+  /* svnserve.conf has been loaded via the --config-file option so need
+   * to load pwdb and authz. */
+  else
+    {
+      SVN_ERR(load_pwdb_config(b, conn, pool));
+      SVN_ERR(load_authz_config(b, conn, repos_root, pool));
+    }
 
 #ifdef SVN_HAVE_SASL
   /* Should we use Cyrus SASL? */
@@ -3349,9 +3351,10 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
   b.user = NULL;
   b.username_case = params->username_case;
   b.authz_user = NULL;
+  b.base = params->base;
   b.cfg = params->cfg;
-  b.pwdb = params->pwdb;
-  b.authzdb = params->authzdb;
+  b.pwdb = NULL;
+  b.authzdb = NULL;
   b.realm = NULL;
   b.log_file = params->log_file;
   b.pool = pool;

Modified: subversion/branches/javahl-ra/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnserve/server.h?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnserve/server.h (original)
+++ subversion/branches/javahl-ra/subversion/svnserve/server.h Fri Dec 28 23:03:51 2012
@@ -42,6 +42,7 @@ typedef struct server_baton_t {
   svn_repos_t *repos;
   const char *repos_name;  /* URI-encoded name of repository (not for authz) */
   svn_fs_t *fs;            /* For convenience; same as svn_repos_fs(repos) */
+  const char *base;        /* Base directory for config files */
   svn_config_t *cfg;       /* Parsed repository svnserve.conf */
   svn_config_t *pwdb;      /* Parsed password database */
   svn_authz_t *authzdb;    /* Parsed authz rules */
@@ -87,24 +88,15 @@ typedef struct serve_params_t {
      which forces all connections to be read-only. */
   svn_boolean_t read_only;
 
+  /* The base directory for any relative configuration files. */
+  const char *base;
+
   /* A parsed repository svnserve configuration file, ala
      svnserve.conf.  If this is NULL, then no configuration file was
      specified on the command line.  If this is non-NULL, then
      per-repository svnserve.conf are not read. */
   svn_config_t *cfg;
 
-  /* A parsed repository password database.  If this is NULL, then
-     either no svnserve configuration file was specified on the
-     command line, or it was specified and it did not refer to a
-     password database. */
-  svn_config_t *pwdb;
-
-  /* A parsed repository authorization database.  If this is NULL,
-     then either no svnserve configuration file was specified on the
-     command line, or it was specified and it did not refer to a
-     authorization database. */
-  svn_authz_t *authzdb;
-
   /* A filehandle open for writing logs to; possibly NULL. */
   apr_file_t *log_file;
 
@@ -145,31 +137,24 @@ typedef struct serve_params_t {
 svn_error_t *serve(svn_ra_svn_conn_t *conn, serve_params_t *params,
                    apr_pool_t *pool);
 
-/* Load a svnserve configuration file located at FILENAME into CFG,
-   and if such as found, then:
+/* Load the password database for the listening server based on the
+   entries in the SERVER struct. 
 
-    - set *PWDB to any referenced password database,
-    - set *AUTHZDB to any referenced authorization database, and
-    - set *USERNAME_CASE to the enumerated value of the
-      'force-username-case' configuration value (or its default).
-
-   If MUST_EXIST is true and FILENAME does not exist, then return an
-   error.  BASE may be specified as the base path to any referenced
-   password and authorization files found in FILENAME.
-
-   If SERVER is not NULL, log the real errors with SERVER and CONN but
-   return generic errors to the client.  CONN must not be NULL if SERVER
-   is not NULL. */
-svn_error_t *load_configs(svn_config_t **cfg,
-                          svn_config_t **pwdb,
-                          svn_authz_t **authzdb,
-                          enum username_case_type *username_case,
-                          const char *filename,
-                          svn_boolean_t must_exist,
-                          const char *base,
-                          server_baton_t *server,
-                          svn_ra_svn_conn_t *conn,
-                          apr_pool_t *pool);
+   SERVER and CONN must not be NULL. The real errors will be logged with
+   SERVER and CONN but return generic errors to the client. */
+svn_error_t *load_pwdb_config(server_baton_t *server,
+                              svn_ra_svn_conn_t *conn,
+                              apr_pool_t *pool);
+
+/* Load the authz database for the listening server based on the
+   entries in the SERVER struct.
+
+   SERVER and CONN must not be NULL. The real errors will be logged with
+   SERVER and CONN but return generic errors to the client. */
+svn_error_t *load_authz_config(server_baton_t *server,
+                               svn_ra_svn_conn_t *conn,
+                               const char *repos_root,
+                               apr_pool_t *pool);
 
 /* Initialize the Cyrus SASL library. POOL is used for allocations. */
 svn_error_t *cyrus_init(apr_pool_t *pool);

Modified: subversion/branches/javahl-ra/subversion/svnserve/svnserve.8
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnserve/svnserve.8?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnserve/svnserve.8 (original)
+++ subversion/branches/javahl-ra/subversion/svnserve/svnserve.8 Fri Dec 28 23:03:51 2012
@@ -110,12 +110,12 @@ still backgrounds itself at startup time
 .TP 5
 \fB\-\-config\-file\fP=\fIfilename\fP
 When specified, \fBsvnserve\fP reads \fIfilename\fP once at program
-startup and caches the \fBsvnserve\fP configuration and any passwords
-and authorization configuration referenced from \fIfilename\fP.
-\fBsvnserve\fP will not read any per-repository
-\fBconf/svnserve.conf\fP files when this option is used.  See the
-\fBsvnserve.conf\fP(5) man page for details of the file format for
-this option.
+startup and caches the \fBsvnserve\fP configuration.  The password
+and authorization configurations referenced from \fIfilename\fP will
+be loaded on each connection.  \fBsvnserve\fP will not read any
+per-repository \fBconf/svnserve.conf\fP files when this option is
+used.  See the \fBsvnserve.conf\fP(5) man page for details of the
+file format for this option.
 .PP
 .TP 5
 \fB\-\-pid\-file\fP=\fIfilename\fP

Modified: subversion/branches/javahl-ra/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnserve/svnserve.c?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/javahl-ra/subversion/svnserve/svnserve.c Fri Dec 28 23:03:51 2012
@@ -1,5 +1,5 @@
 /*
- * main.c :  Main control function for svnserve
+ * svnserve.c :  Main control function for svnserve
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -503,9 +503,8 @@ int main(int argc, const char *argv[])
   params.tunnel = FALSE;
   params.tunnel_user = NULL;
   params.read_only = FALSE;
+  params.base = NULL;
   params.cfg = NULL;
-  params.pwdb = NULL;
-  params.authzdb = NULL;
   params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
   params.log_file = NULL;
   params.vhost = FALSE;
@@ -747,11 +746,14 @@ int main(int argc, const char *argv[])
   /* If a configuration file is specified, load it and any referenced
    * password and authorization files. */
   if (config_filename)
-    SVN_INT_ERR(load_configs(&params.cfg, &params.pwdb, &params.authzdb,
-                             &params.username_case, config_filename, TRUE,
-                             svn_dirent_dirname(config_filename, pool),
-                             NULL, NULL, /* server baton, conn */
-                             pool));
+    {
+      params.base = svn_dirent_dirname(config_filename, pool);
+
+      SVN_INT_ERR(svn_config_read2(&params.cfg, config_filename,
+                                   TRUE, /* must_exist */
+                                   FALSE, /* section_names_case_sensitive */
+                                   pool));
+    }
 
   if (log_filename)
     SVN_INT_ERR(svn_io_file_open(&params.log_file, log_filename,

Modified: subversion/branches/javahl-ra/subversion/svnserve/svnserve.conf.5
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svnserve/svnserve.conf.5?rev=1426654&r1=1426653&r2=1426654&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svnserve/svnserve.conf.5 (original)
+++ subversion/branches/javahl-ra/subversion/svnserve/svnserve.conf.5 Fri Dec 28 23:03:51 2012
@@ -61,11 +61,13 @@ uses only one section "users"; each vari
 username, and each value is a password.
 .PP
 .TP 5
-\fBauthz-db\fP = \fIfilename\fP
+\fBauthz-db\fP = \fIpath\fP
 The authz-db option controls the location of the authorization
-rules for path-based access control.  \fIfilename\fP may be 
-relative to the repository conf directory.  There is no default value.
-If you don't specify an authz-db, no path-based access control is done.
+rules for path-based access control.  \fIpath\fP may be 
+relative to the repository conf directory.  \fIpath\fP may be a repository
+relative URL (^/) or absolute file:// URL to a text file in a Subversion
+repository.  There is no default value.  If you don't specify an authz-db,
+no path-based access control is done.
 .PP
 .TP 5
 \fBrealm\fP = \fIrealm\-name\fP



Mime
View raw message