svn-3416

Version:

1.6.x

Bug Link:

http://subversion.tigris.org/issues/show_bug.cgi?id=3416

Patch Link:

source code patch: http://svn.apache.org/viewvc?diff_format=h&view=revision&revision=878062

reproduction: http://subversion.tigris.org/nonav/issues/showattachment.cgi/998/svn-bug-repro

Symptom:

Cannot ‘svn add’ or ‘svn commit’ a file of starting with ‘@’. For example, ‘dir/@file.txt@’ cannot be added.

“svn: warning: 'dir/@File.txt@' not found”

How it is diagnosed:

reproduced

How to reproduce:

‘svn add dir/@File.txt@’ doesn’t work with the error message, “svn: warning: 'dir/@File.txt@' not found”

 

There’s a work-around:

                ‘cd dir’; ‘svn add’@File.txt’’; ‘cd ..’

Root Cause:

Brief:

No parsing routine of handling the file name starting with ‘@’ sign.

Detail:

Where the error message was printed:

svn_error_t *svn_wc_add3(... ...) {

   … ...

 

  SVN_ERR(svn_path_check_valid(path, pool));

 

  /* This svn_io_check_path is a wrapper to ‘stat’ system call.  */

  SVN_ERR(svn_io_check_path(path, &kind, pool));

  if (kind == svn_node_none)

        return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,

                         _("'%s' not found"),

                             svn_path_local_style(path, pool));

// ‘dir/@File.txt’ does not exist

}

Patch:

adds new function ‘svn_opt_eat_peg_revisions’ to handle the filename properly.

In every commands, adds the code calling ‘svn_opt_eat_peg_revisions’.

 

--- subversion/trunk/subversion/libsvn_subr/opt.c   2009/06/11 12:58:46            878061

+++ subversion/trunk/subversion/libsvn_subr/opt.c 2009/06/11 14:45:47            878062

@@ -873,12 +873,21 @@ svn_opt__split_arg_at_peg_revision(const

 

   if (peg_start)

         {

+          /* Error out if target is the empty string. */

// added the new error log message

+          if (j == 0)

+            return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,

+                                     _("'%s' is just a peg revision. "

+                                       "Maybe try '%s@' instead?"),

+                                     utf8_target, utf8_target);

+

           *true_target = apr_pstrmemdup(pool, utf8_target, j);

+          if (peg_revision)

       *peg_revision = apr_pstrdup(pool, peg_start);

         }

   else

         {

           *true_target = utf8_target;

+          if (peg_revision)

       *peg_revision = "";

         }

 

@@ -1018,3 +1027,29 @@ svn_opt_print_help3(apr_getopt_t *os,

 

   return SVN_NO_ERROR;

 }

+

+svn_error_t *

+svn_opt_eat_peg_revisions(apr_array_header_t **true_targets_p,

+                              apr_array_header_t *targets,

+                              apr_pool_t *pool)

+{

+  unsigned int i;

+  apr_array_header_t *true_targets;

+

+  true_targets = apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));

+

+  for (i = 0; i < targets->nelts; i++)

+        {

+          const char *target = APR_ARRAY_IDX(targets, i, const char *);

+          const char *true_target;

+

+          SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, NULL,

+                                                 target, pool));

+      APR_ARRAY_PUSH(true_targets, const char *) = true_target;

+        }

+

+  SVN_ERR_ASSERT(true_targets_p);

+  *true_targets_p = true_targets;

+

+  return SVN_NO_ERROR;

+}

// adds a new function to handle the ‘@’ sign properly.

 

--- subversion/trunk/subversion/svn/add-cmd.c           2009/06/11 12:58:46            878061

+++ subversion/trunk/subversion/svn/add-cmd.c         2009/06/11 14:45:47            878062

@@ -59,6 +59,8 @@ svn_cl__add(apr_getopt_t *os,

   if (opt_state->depth == svn_depth_unknown)

         opt_state->depth = svn_depth_infinity;

 

+  SVN_ERR(svn_opt_eat_peg_revisions(&targets, targets, pool));

+

// path with ‘@’ sign handling routine

 

   subpool = svn_pool_create(pool);

   for (i = 0; i < targets->nelts; i++)

         {

 

call stack:

 

#0  svn_wc_add3 (path="dir/@File.txt@", depth=svn_depth_infinity) at subversion/libsvn_wc/adm_ops.c:1363

#1  add (path="dir/@File.txt@", depth=svn_depth_infinity) at subversion/libsvn_client/add.c:484

#2  svn_client_add4 (path="dir/@File.txt@", depth=svn_depth_infinity) at subversion/libsvn_client/add.c:588

#3  svn_cl__add () at subversion/svn/add-cmd.c:69

#4  main () at subversion/svn/main.c:2123

 

 

svn_error_t *

svn_wc_add3(const char *path,

                svn_wc_adm_access_t *parent_access,

                svn_depth_t depth,

                const char *copyfrom_url,

                svn_revnum_t copyfrom_rev,

                svn_cancel_func_t cancel_func,

                void *cancel_baton,

                svn_wc_notify_func2_t notify_func,

                void *notify_baton,

                apr_pool_t *pool)

{

  const char *parent_dir, *base_name;

  const svn_wc_entry_t *orig_entry, *parent_entry;

  svn_wc_entry_t tmp_entry;

  svn_boolean_t is_replace = FALSE;

  svn_node_kind_t kind;

  apr_uint64_t modify_flags = 0;

  svn_wc_adm_access_t *adm_access;

 

  SVN_ERR(svn_path_check_valid(path, pool));

 

  /* Make sure something's there. */

  SVN_ERR(svn_io_check_path(path, &kind, pool));

  if (kind == svn_node_none)

        return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,

                                 _("'%s' not found"),

                             svn_path_local_style(path, pool));

// ‘dir/@File.txt’ does not exist

 

svn_error_t *

svn_cl__add(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_array_header_t *targets;

  int i;

  apr_pool_t *subpool;

 

  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,

                                                      opt_state->targets,

                                                      ctx, pool));

 

  if (! targets->nelts)

        return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

 

  if (! opt_state->quiet)

    svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE,

                             FALSE, FALSE, pool);

 

  if (opt_state->depth == svn_depth_unknown)

        opt_state->depth = svn_depth_infinity;

 

  subpool = svn_pool_create(pool);

  for (i = 0; i < targets->nelts; i++)

        {

          const char *target = APR_ARRAY_IDX(targets, i, const char *);

 

          svn_pool_clear(subpool);

      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

          SVN_ERR(svn_cl__try

                  (svn_client_add4(target,

                               opt_state->depth,

                               opt_state->force, opt_state->no_ignore,

                                   opt_state->parents, ctx, subpool),

               NULL, opt_state->quiet,

               SVN_ERR_ENTRY_EXISTS,

               SVN_ERR_WC_PATH_NOT_FOUND,

               SVN_NO_ERROR));

 

// ‘svn_cl__try’ makes ‘warning log message’, and ‘svn_client_add4’ makes an error.

Failure symptom category

refuse valid input, early termination

Is there any log message?

Yes (warning message)

Can it be automatically inserted?

Yes. Function return value, checked -- stat.