svn-3745

Version:

1.6.13

Bug Link:

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

http://svn.haxx.se/users/archive-2010-11/0129.shtml

Patch Link:

http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/patch.c?diff_format=h&r1=907617&r2=907616&pathrev=907617

Symptom:

svn export mistakenly uri-encodes the blank in paths to %20

How it is diagnosed:

reproduced!

$cd repository

$svnadmin create xx

$cd ../wc

$svn co file:///home/yyzhou/peh003/repository/xx xx

$cd xx

$svn mkdir "1 2"

A         1 2

$echo whosyourdaddy > "1 2/yy"

$svn add "1 2/yy"

A         1 2/yy

$svn ci -m "test"

Adding         1 2

Adding         1 2/yy

Transmitting file data .c

Committed revision 1.  

$svn up

At revision 2.

$svn ls -r head -v "1 2"

     2 peh003                Jan 14 13:34 ./

     2 peh003             14 Jan 14 13:34 yy

$svn export "1 2" X

svn: '1%202' is not under version control

Root Cause:

Brief:

The export source argument(in the case above it’s “1 2”) is unconditionally encoded with svn_uri_encode(), which will encode blank to %20. The uri encoding should only be done on URLs but not local path.

Detail:


/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__export(...)
{
 ...
 const char *from, *to;
 ...
 const char *truefrom;
 ...
 /* The first target is the `from' path. */
 from = APR_ARRAY_IDX(targets, 0, const char *);
// in the example, it’s “1 2”
  ...
 if (targets->nelts == 1)

// in the example, it’s “X”
          to = svn_path_uri_decode(svn_path_basename(truefrom, pool), pool);
 else
     ...
 …

//we should only encode if the source is a url

+ if (svn_path_is_url(truefrom))

// now it will change ‘from’ to "1%202"
          truefrom = svn_path_uri_encode(svn_path_uri_adecode(truefrom, pool), pool);

 /* Do the export. */
 err =
svn_client_export4(NULL, truefrom, to, &peg_revision,
                          &(opt_state->start_revision),
                          opt_state->force, opt_state->ignore_externals,
                          opt_state->depth,
                          opt_state->native_eol, ctx,
                          pool);
 if (err && err->apr_err == SVN_ERR_WC_OBSTRUCTED_UPDATE && !opt_state->force)
   SVN_ERR_W(err,
             _("Destination directory exists; please remove "
               "the directory or use --force to overwrite"));

 return err;
}

Where the error message is created?

svn_error_t * svn_client_export4(...)

{

        …

if (svn_path_is_url(from) ||

     ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))

        ...

else // from = "1%202", revision->kind = svn_opt_revision_working

{

     /* This is a working copy export. */

     /* just copy the contents of the working copy into the target path. */

     SVN_ERR(copy_versioned_files(from, to, revision, overwrite,

                                  ignore_externals, depth, native_eol,

                                  ctx, pool));

}

        

}

static svn_error_t * copy_versioned_files(...)

{

        ...

        SVN_ERR(svn_wc__entry_versioned(&entry, from, adm_access, FALSE, pool));

        ...

}

svn_error_t * svn_wc__entry_versioned_internal(...)

{

 SVN_ERR(svn_wc_entry(entry, path, adm_access, show_hidden, pool));

  /* This is where the error message was printed!!! */

 if (! *entry)//it wil be set to NULL, since  cannot find “1%202” in current directory

   {

     svn_error_t *err

       = svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,

                           _("'%s' is not under version control"),

                           svn_path_local_style(path, pool));

     err->file = caller_filename;

     err->line = caller_lineno;

     return err;

   }

 return SVN_NO_ERROR;

}

svn_error_t * svn_wc_entry(...)

{

 const char *entry_name;

 svn_wc_adm_access_t *dir_access;

 SVN_ERR(svn_wc__adm_retrieve_internal(&dir_access, adm_access, path, pool));

 if (! dir_access)

   {

const char *dir_path, *base_name;

/**path is "1%202", after split, dir_path="", base_name="1%202"**/

svn_path_split(path, &dir_path, &base_name, pool);

SVN_ERR(svn_wc__adm_retrieve_internal(&dir_access, adm_access, dir_path,

                                           pool));//here, dir_access is set for “”

entry_name = base_name;

   }

 else

          ...

 if (dir_access)

 {

     apr_hash_t *entries;

     //there’s no base name “1%202” in dir_path “”.

     SVN_ERR(svn_wc_entries_read(&entries, dir_access, show_hidden, pool));

     //so *entry is set to NULL

     *entry = apr_hash_get(entries, entry_name, APR_HASH_KEY_STRING);

 }

 else

   *entry = NULL;

   return SVN_NO_ERROR;

}

Failure symptom category

refusing valid input/early termination

Is there any log message?

Yes

How can ErrLog automatically insert error messag?

return value check.