Exemple #1
0
static svn_error_t *
reporter_link_path(void *reporter_baton,
                   const char *path,
                   const char *url,
                   svn_revnum_t revision,
                   svn_depth_t depth,
                   svn_boolean_t start_empty,
                   const char *lock_token,
                   apr_pool_t *pool)
{
  reporter_baton_t *rbaton = reporter_baton;
  const char *fs_path = NULL;
  const char *repos_url_decoded;
  int repos_url_len;

  url = svn_path_uri_decode(url, pool);
  repos_url_decoded = svn_path_uri_decode(rbaton->sess->repos_url, pool);
  repos_url_len = strlen(repos_url_decoded);
  if (strncmp(url, repos_url_decoded, repos_url_len) != 0)
    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                             _("'%s'\n"
                               "is not the same repository as\n"
                               "'%s'"), url, rbaton->sess->repos_url);
  fs_path = url + repos_url_len;
  return svn_repos_link_path3(rbaton->report_baton, path, fs_path, revision,
                              depth, start_empty, lock_token, pool);
}
Exemple #2
0
static svn_error_t *
svn_ra_local__reparent(svn_ra_session_t *session,
                       const char *url,
                       apr_pool_t *pool)
{
  svn_ra_local__session_baton_t *sess = session->priv;
  const char *relpath = "";

  /* If the new URL isn't the same as our repository root URL, then
     let's ensure that it's some child of it. */
  if (strcmp(url, sess->repos_url) != 0)
    relpath = svn_path_is_child(sess->repos_url, url, pool);
  if (! relpath)
    return svn_error_createf
      (SVN_ERR_RA_ILLEGAL_URL, NULL,
       _("URL '%s' is not a child of the session's repository root "
         "URL '%s'"), url, sess->repos_url);

  /* Update our FS_PATH sess member to point to our new
     relative-URL-turned-absolute-filesystem-path. */
  relpath = apr_pstrcat(pool, "/", svn_path_uri_decode(relpath, pool), NULL);
  svn_stringbuf_set(sess->fs_path, relpath);

  return SVN_NO_ERROR;
}
Exemple #3
0
/* This implements the 'svn_ra_get_wc_prop_func_t' interface. */
static svn_error_t *
get_wc_prop(void *baton,
            const char *relpath,
            const char *name,
            const svn_string_t **value,
            apr_pool_t *pool)
{
  svn_client__callback_baton_t *cb = baton;

  *value = NULL;

  /* If we have a list of commit_items, search through that for a
     match for this relative URL. */
  if (cb->commit_items)
    {
      int i;
      for (i = 0; i < cb->commit_items->nelts; i++)
        {
          svn_client_commit_item3_t *item
            = APR_ARRAY_IDX(cb->commit_items, i,
                            svn_client_commit_item3_t *);
          if (! strcmp(relpath,
                       svn_path_uri_decode(item->url, pool)))
            return svn_wc_prop_get(value, name, item->path, cb->base_access,
                                   pool);
        }

      return SVN_NO_ERROR;
    }
Exemple #4
0
  std::string
  Url::unescape(const char * url)
  {
    Pool pool;

    return svn_path_uri_decode(url, pool);
  }
Exemple #5
0
/* Return the portion of URL that is relative to ANCHOR. */
static const char *
subtract_anchor(const char *anchor, const char *url, apr_pool_t *pool)
{
  if (! strcmp(url, anchor))
    return "";
  else
    return svn_path_uri_decode(svn_path_is_child(anchor, url, pool), pool);
}
Exemple #6
0
QString svn::InfoEntry::prettyUrl(const char*_url)const
{
    if (_url) {
        Pool pool;
        _url = svn_path_uri_decode(_url,pool);
        return QString::fromUtf8(_url);
    }
    return QString::fromUtf8("");
}
Exemple #7
0
static svn_error_t *
change_dir_prop(void *dir_baton,
                const char *name,
                const svn_string_t *value,
                apr_pool_t *pool)
{
  node_baton_t *db = dir_baton;
  edit_baton_t *eb = db->edit_baton;

  /* Only regular properties can pass over libsvn_ra */
  if (svn_property_kind2(name) != svn_prop_regular_kind)
    return SVN_NO_ERROR;

  /* Maybe drop svn:mergeinfo.  */
  if (eb->strip_mergeinfo && (strcmp(name, SVN_PROP_MERGEINFO) == 0))
    {
      eb->mergeinfo_stripped = TRUE;
      return SVN_NO_ERROR;
    }

  /* Maybe convert svnmerge-integrated data into svn:mergeinfo.  (We
     ignore svnmerge-blocked for now.) */
  /* ### FIXME: Consult the mirror repository's HEAD prop values and
     ### merge svn:mergeinfo, svnmerge-integrated, and svnmerge-blocked. */
  if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-integrated") == 0))
    {
      if (value)
        {
          /* svnmerge-integrated differs from svn:mergeinfo in a pair
             of ways.  First, it can use tabs, newlines, or spaces to
             delimit source information.  Secondly, the source paths
             are relative URLs, whereas svn:mergeinfo uses relative
             paths (not URI-encoded). */
          svn_error_t *err;
          svn_stringbuf_t *mergeinfo_buf = svn_stringbuf_create_empty(pool);
          svn_mergeinfo_t mergeinfo;
          int i;
          apr_array_header_t *sources =
            svn_cstring_split(value->data, " \t\n", TRUE, pool);
          svn_string_t *new_value;

          for (i = 0; i < sources->nelts; i++)
            {
              const char *rel_path;
              apr_array_header_t *path_revs =
                svn_cstring_split(APR_ARRAY_IDX(sources, i, const char *),
                                  ":", TRUE, pool);

              /* ### TODO: Warn? */
              if (path_revs->nelts != 2)
                continue;

              /* Append this source's mergeinfo data. */
              rel_path = APR_ARRAY_IDX(path_revs, 0, const char *);
              rel_path = svn_path_uri_decode(rel_path, pool);
              svn_stringbuf_appendcstr(mergeinfo_buf, rel_path);
              svn_stringbuf_appendcstr(mergeinfo_buf, ":");
              svn_stringbuf_appendcstr(mergeinfo_buf,
                                       APR_ARRAY_IDX(path_revs, 1,
                                                     const char *));
              svn_stringbuf_appendcstr(mergeinfo_buf, "\n");
            }

          /* Try to parse the mergeinfo string we've created, just to
             check for bogosity.  If all goes well, we'll unparse it
             again and use that as our property value.  */
          err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_buf->data, pool);
          if (err)
            {
              svn_error_clear(err);
              return SVN_NO_ERROR;
            }
          SVN_ERR(svn_mergeinfo_to_string(&new_value, mergeinfo, pool));
          value = new_value;
        }
      name = SVN_PROP_MERGEINFO;
      eb->svnmerge_migrated = TRUE;
    }

  /* Remember if we see any svnmerge-blocked properties. */
  if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-blocked") == 0))
    {
      eb->svnmerge_blocked = TRUE;
    }

  /* Normalize svn:* properties as necessary. */
  if (svn_prop_needs_translation(name))
    {
      svn_boolean_t was_normalized;
      svn_boolean_t mergeinfo_tweaked = FALSE;

      /* Normalize encoding to UTF-8, and EOL style to LF. */
      SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding,
                               pool, pool));
      /* Maybe adjust svn:mergeinfo. */
      if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
        {
          SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
                                      pool, pool));
          if (mergeinfo_tweaked)
            eb->mergeinfo_tweaked = TRUE;
        }
      if (was_normalized)
        (*(eb->normalized_node_props_counter))++;
    }

  return eb->wrapped_editor->change_dir_prop(db->wrapped_node_baton,
                                             name, value, pool);
}
Exemple #8
0
svn_error_t *
svn_client_info2(const char *path_or_url,
                 const svn_opt_revision_t *peg_revision,
                 const svn_opt_revision_t *revision,
                 svn_info_receiver_t receiver,
                 void *receiver_baton,
                 svn_depth_t depth,
                 const apr_array_header_t *changelists,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *pool)
{
  svn_ra_session_t *ra_session, *parent_ra_session;
  svn_revnum_t rev;
  const char *url;
  svn_node_kind_t url_kind;
  const char *repos_root_URL, *repos_UUID;
  svn_lock_t *lock;
  svn_boolean_t related;
  apr_hash_t *parent_ents;
  const char *parent_url, *base_name;
  svn_dirent_t *the_ent;
  svn_info_t *info;
  svn_error_t *err;

  if ((revision == NULL
       || revision->kind == svn_opt_revision_unspecified)
      && (peg_revision == NULL
          || peg_revision->kind == svn_opt_revision_unspecified))
    {
      /* Do all digging in the working copy. */
      apr_hash_t *changelist_hash = NULL;
      if (changelists && changelists->nelts)
        SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, 
                                           changelists, pool));
      return crawl_entries(path_or_url, receiver, receiver_baton,
                           depth, changelist_hash, ctx, pool);
    }

  /* Go repository digging instead. */

  /* Trace rename history (starting at path_or_url@peg_revision) and
     return RA session to the possibly-renamed URL as it exists in REVISION.
     The ra_session returned will be anchored on this "final" URL. */
  SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev,
                                           &url, path_or_url, NULL,
                                           peg_revision,
                                           revision, ctx, pool));

  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_URL, pool));
  SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_UUID, pool));

  svn_path_split(url, &parent_url, &base_name, pool);
  base_name = svn_path_uri_decode(base_name, pool);

  /* Get the dirent for the URL itself. */
  err = svn_ra_stat(ra_session, "", rev, &the_ent, pool);

  /* svn_ra_stat() will work against old versions of mod_dav_svn, but
     not old versions of svnserve.  In the case of a pre-1.2 svnserve,
     catch the specific error it throws:*/
  if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
    {
      /* Fall back to pre-1.2 strategy for fetching dirent's URL. */
      svn_error_clear(err);

      if (strcmp(url, repos_root_URL) == 0)
        {
          /* In this universe, there's simply no way to fetch
             information about the repository's root directory!
             If we're recursing, degrade gracefully: rather than
             throw an error, return no information about the
             repos root. */
          if (depth > svn_depth_empty)
            goto pre_1_2_recurse;

          /* Otherwise, we really are stuck.  Better tell the user
             what's going on. */
          return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                   _("Server does not support retrieving "
                                     "information about the repository root"));
        }

      SVN_ERR(svn_ra_check_path(ra_session, "", rev, &url_kind, pool));
      if (url_kind == svn_node_none)
        return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                                 _("URL '%s' non-existent in revision %ld"),
                                 url, rev);

      /* Open a new RA session to the item's parent. */
      SVN_ERR(svn_client__open_ra_session_internal(&parent_ra_session,
                                                   parent_url, NULL,
                                                   NULL, NULL, FALSE, TRUE,
                                                   ctx, pool));

      /* Get all parent's entries, and find the item's dirent in the hash. */
      SVN_ERR(svn_ra_get_dir2(parent_ra_session, &parent_ents, NULL, NULL,
                              "", rev, DIRENT_FIELDS, pool));
      the_ent = apr_hash_get(parent_ents, base_name, APR_HASH_KEY_STRING);
      if (the_ent == NULL)
        return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                                 _("URL '%s' non-existent in revision %ld"),
                                 url, rev);
    }
  else if (err)
    {
      return err;
    }

  if (! the_ent)
    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                             _("URL '%s' non-existent in revision %ld"),
                             url, rev);

  /* Check if the URL exists in HEAD and refers to the same resource.
     In this case, we check the repository for a lock on this URL.

     ### There is a possible race here, since HEAD might have changed since
     ### we checked it.  A solution to this problem could be to do the below
     ### check in a loop which only terminates if the HEAD revision is the same
     ### before and after this check.  That could, however, lead to a
     ### starvation situation instead.  */
  SVN_ERR(same_resource_in_head(&related, url, rev, ra_session, ctx, pool));
  if (related)
    {
      err = svn_ra_get_lock(ra_session, &lock, "", pool);

      /* An old mod_dav_svn will always work; there's nothing wrong with
         doing a PROPFIND for a property named "DAV:supportedlock". But
         an old svnserve will error. */
      if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
        {
          svn_error_clear(err);
          lock = NULL;
        }
      else if (err)
        return err;
    }
  else
    lock = NULL;

  /* Push the URL's dirent (and lock) at the callback.*/
  SVN_ERR(build_info_from_dirent(&info, the_ent, lock, url, rev,
                                 repos_UUID, repos_root_URL, pool));
  SVN_ERR(receiver(receiver_baton, base_name, info, pool));

  /* Possibly recurse, using the original RA session. */
  if (depth > svn_depth_empty && (the_ent->kind == svn_node_dir))
    {
      apr_hash_t *locks;

pre_1_2_recurse:
      if (peg_revision->kind == svn_opt_revision_head)
        {
          err = svn_ra_get_locks(ra_session, &locks, "", pool);

          /* Catch specific errors thrown by old mod_dav_svn or svnserve. */
          if (err &&
              (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED
               || err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
            {
              svn_error_clear(err);
              locks = apr_hash_make(pool); /* use an empty hash */
            }
          else if (err)
            return err;
        }
      else
        locks = apr_hash_make(pool); /* use an empty hash */

      SVN_ERR(push_dir_info(ra_session, url, "", rev,
                            repos_UUID, repos_root_URL,
                            receiver, receiver_baton,
                            depth, ctx, locks, pool));
    }

  return SVN_NO_ERROR;
}
Exemple #9
0
/* Helper func for recursively fetching svn_dirent_t's from a remote
   directory and pushing them at an info-receiver callback.

   DEPTH is the depth starting at DIR, even though RECEIVER is never
   invoked on DIR: if DEPTH is svn_depth_immediates, then invoke
   RECEIVER on all children of DIR, but none of their children; if
   svn_depth_files, then invoke RECEIVER on file children of DIR but
   not on subdirectories; if svn_depth_infinity, recurse fully.
*/
static svn_error_t *
push_dir_info(svn_ra_session_t *ra_session,
              const char *session_URL,
              const char *dir,
              svn_revnum_t rev,
              const char *repos_UUID,
              const char *repos_root,
              svn_info_receiver_t receiver,
              void *receiver_baton,
              svn_depth_t depth,
              svn_client_ctx_t *ctx,
              apr_hash_t *locks,
              apr_pool_t *pool)
{
  apr_hash_t *tmpdirents;
  svn_dirent_t *the_ent;
  svn_info_t *info;
  apr_hash_index_t *hi;
  apr_pool_t *subpool = svn_pool_create(pool);

  SVN_ERR(svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
                          dir, rev, DIRENT_FIELDS, pool));

  for (hi = apr_hash_first(pool, tmpdirents); hi; hi = apr_hash_next(hi))
    {
      const char *path, *URL, *fs_path;
      const void *key;
      svn_lock_t *lock;
      void *val;

      svn_pool_clear(subpool);

      if (ctx->cancel_func)
        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));

      apr_hash_this(hi, &key, NULL, &val);
      the_ent = val;

      path = svn_path_join(dir, key, subpool);
      URL  = svn_path_url_add_component(session_URL, key, subpool);

      fs_path = svn_path_is_child(repos_root, URL, subpool);
      fs_path = apr_pstrcat(subpool, "/", fs_path, NULL);
      fs_path = svn_path_uri_decode(fs_path, subpool);

      lock = apr_hash_get(locks, fs_path, APR_HASH_KEY_STRING);

      SVN_ERR(build_info_from_dirent(&info, the_ent, lock, URL, rev,
                                     repos_UUID, repos_root, subpool));

      if (depth >= svn_depth_immediates
          || (depth == svn_depth_files && the_ent->kind == svn_node_file))
        {
          SVN_ERR(receiver(receiver_baton, path, info, subpool));
        }

      if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
        {
          SVN_ERR(push_dir_info(ra_session, URL, path,
                                rev, repos_UUID, repos_root,
                                receiver, receiver_baton,
                                depth, ctx, locks, subpool));
        }
    }

  svn_pool_destroy(subpool);

  return SVN_NO_ERROR;
}
Exemple #10
0
static svn_error_t *
svn_ra_local__get_commit_editor(svn_ra_session_t *session,
                                const svn_delta_editor_t **editor,
                                void **edit_baton,
                                apr_hash_t *revprop_table,
                                svn_commit_callback2_t callback,
                                void *callback_baton,
                                apr_hash_t *lock_tokens,
                                svn_boolean_t keep_locks,
                                apr_pool_t *pool)
{
  svn_ra_local__session_baton_t *sess = session->priv;
  struct deltify_etc_baton *db = apr_palloc(pool, sizeof(*db));
  apr_hash_index_t *hi;
  svn_fs_access_t *fs_access;

  db->fs = sess->fs;
  db->repos = sess->repos;
  db->fs_path = sess->fs_path->data;
  if (! keep_locks)
    db->lock_tokens = lock_tokens;
  else
    db->lock_tokens = NULL;
  db->pool = pool;
  db->callback = callback;
  db->callback_baton = callback_baton;

  SVN_ERR(get_username(session, pool));

  /* If there are lock tokens to add, do so. */
  if (lock_tokens)
    {
      SVN_ERR(svn_fs_get_access(&fs_access, sess->fs));

      /* If there is no access context, the filesystem will scream if a
         lock is needed. */
      if (fs_access)
        {
          for (hi = apr_hash_first(pool, lock_tokens); hi;
               hi = apr_hash_next(hi))
            {
              void *val;
              const char *path, *token;
              const void *key;

              apr_hash_this(hi, &key, NULL, &val);
              path = svn_path_join(sess->fs_path->data, (const char *)key,
                                   pool);
              token = val;
              SVN_ERR(svn_fs_access_add_lock_token2(fs_access, path, token));
            }
        }
    }

  /* Copy the revprops table so we can add the username. */
  revprop_table = apr_hash_copy(pool, revprop_table);
  apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING,
               svn_string_create(sess->username, pool));

  /* Get the repos commit-editor */
  return svn_repos_get_commit_editor5
         (editor, edit_baton, sess->repos, NULL,
          svn_path_uri_decode(sess->repos_url, pool), sess->fs_path->data,
          revprop_table, deltify_etc, db, NULL, NULL, pool);
}
Exemple #11
0
/* This function is the shared guts of add_file() and add_directory(),
   which see for the meanings of the parameters.  The only extra
   parameter here is IS_DIR, which is TRUE when adding a directory,
   and FALSE when adding a file.  */
static svn_error_t *
add_file_or_directory(const char *path,
                      void *parent_baton,
                      const char *copy_path,
                      svn_revnum_t copy_revision,
                      svn_boolean_t is_dir,
                      apr_pool_t *pool,
                      void **return_baton)
{
  struct dir_baton *pb = parent_baton;
  struct edit_baton *eb = pb->edit_baton;
  apr_pool_t *subpool = svn_pool_create(pool);
  svn_boolean_t was_copied = FALSE;
  const char *full_path;

  full_path = svn_fspath__join(eb->base_path,
                               svn_relpath_canonicalize(path, pool), pool);

  /* Sanity check. */
  if (copy_path && (! SVN_IS_VALID_REVNUM(copy_revision)))
    return svn_error_createf
      (SVN_ERR_FS_GENERAL, NULL,
       _("Got source path but no source revision for '%s'"), full_path);

  if (copy_path)
    {
      const char *fs_path;
      svn_fs_root_t *copy_root;
      svn_node_kind_t kind;
      size_t repos_url_len;
      svn_repos_authz_access_t required;

      /* Copy requires recursive write access to the destination path
         and write access to the parent path. */
      required = svn_authz_write | (is_dir ? svn_authz_recursive : 0);
      SVN_ERR(check_authz(eb, full_path, eb->txn_root,
                          required, subpool));
      SVN_ERR(check_authz(eb, pb->path, eb->txn_root,
                          svn_authz_write, subpool));

      /* Check PATH in our transaction.  Make sure it does not exist
         unless its parent directory was copied (in which case, the
         thing might have been copied in as well), else return an
         out-of-dateness error. */
      SVN_ERR(svn_fs_check_path(&kind, eb->txn_root, full_path, subpool));
      if ((kind != svn_node_none) && (! pb->was_copied))
        return out_of_date(full_path, kind);

      /* For now, require that the url come from the same repository
         that this commit is operating on. */
      copy_path = svn_path_uri_decode(copy_path, subpool);
      repos_url_len = strlen(eb->repos_url);
      if (strncmp(copy_path, eb->repos_url, repos_url_len) != 0)
        return svn_error_createf
          (SVN_ERR_FS_GENERAL, NULL,
           _("Source url '%s' is from different repository"), copy_path);

      fs_path = apr_pstrdup(subpool, copy_path + repos_url_len);

      /* Now use the "fs_path" as an absolute path within the
         repository to make the copy from. */
      SVN_ERR(svn_fs_revision_root(&copy_root, eb->fs,
                                   copy_revision, subpool));

      /* Copy also requires (recursive) read access to the source */
      required = svn_authz_read | (is_dir ? svn_authz_recursive : 0);
      SVN_ERR(check_authz(eb, fs_path, copy_root, required, subpool));

      SVN_ERR(svn_fs_copy(copy_root, fs_path,
                          eb->txn_root, full_path, subpool));
      was_copied = TRUE;
    }
  else
    {
      /* No ancestry given, just make a new directory or empty file.
         Note that we don't perform an existence check here like the
         copy-from case does -- that's because svn_fs_make_*()
         already errors out if the file already exists.  Verify write
         access to the full path and to the parent. */
      SVN_ERR(check_authz(eb, full_path, eb->txn_root,
                          svn_authz_write, subpool));
      SVN_ERR(check_authz(eb, pb->path, eb->txn_root,
                          svn_authz_write, subpool));
      if (is_dir)
        SVN_ERR(svn_fs_make_dir(eb->txn_root, full_path, subpool));
      else
        SVN_ERR(svn_fs_make_file(eb->txn_root, full_path, subpool));
    }

  /* Cleanup our temporary subpool. */
  svn_pool_destroy(subpool);

  /* Build a new child baton. */
  if (is_dir)
    {
      *return_baton = make_dir_baton(eb, pb, full_path, was_copied,
                                     SVN_INVALID_REVNUM, pool);
    }
  else
    {
      struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
      new_fb->edit_baton = eb;
      new_fb->path = full_path;
      *return_baton = new_fb;
    }

  return SVN_NO_ERROR;
}
Exemple #12
0
svn_error_t *
svn_ra_local__split_URL(svn_repos_t **repos,
                        const char **repos_url,
                        const char **fs_path,
                        const char *URL,
                        apr_pool_t *pool)
{
  svn_error_t *err = SVN_NO_ERROR;
  const char *repos_root;
  const char *hostname, *path;
  svn_stringbuf_t *urlbuf;

  /* Verify that the URL is well-formed (loosely) */

  /* First, check for the "file://" prefix. */
  if (strncmp(URL, "file://", 7) != 0)
    return svn_error_createf
      (SVN_ERR_RA_ILLEGAL_URL, NULL,
       _("Local URL '%s' does not contain 'file://' prefix"), URL);

  /* Then, skip what's between the "file://" prefix and the next
     occurance of '/' -- this is the hostname, and we are considering
     everything from that '/' until the end of the URL to be the
     absolute path portion of the URL.
     If we got just "file://", treat it the same as "file:///". */
  hostname = URL + 7;
  if (*hostname == '\0')
    {
      path = "/";
      hostname = NULL;
    }
  else
    {
      path = strchr(hostname, '/');
      if (! path)
        return svn_error_createf
          (SVN_ERR_RA_ILLEGAL_URL, NULL,
           _("Local URL '%s' contains only a hostname, no path"), URL);

      /* Treat localhost as an empty hostname. */
      if (hostname != path)
        {
          hostname = svn_path_uri_decode(apr_pstrmemdup(pool, hostname,
                                                        path - hostname), pool);
          if (strncmp(hostname, "localhost", 9) == 0)
            hostname = NULL;
        }
      else
        hostname = NULL;
    }

  /* Duplicate the URL, starting at the top of the path.
     At the same time, we URI-decode the path. */
#if defined(WIN32) || defined(__CYGWIN__)
  /* On Windows, we'll typically have to skip the leading / if the
     path starts with a drive letter.  Like most Web browsers, We
     support two variants of this scheme:

         file:///X:/path    and
         file:///X|/path

    Note that, at least on WinNT and above,  file:////./X:/path  will
    also work, so we must make sure the transformation doesn't break
    that, and  file:///path  (that looks within the current drive
    only) should also keep working.
    If we got a non-empty hostname other than localhost, we convert this
    into an UNC path.  In this case, we obviously don't strip the slash
    even if the path looks like it starts with a drive letter.
    Another thing to remember is that the form file:///\machine/share
    was the only way to access UNC paths in svn before 1.2.  We
    need to support that for compatibility with old working copies.
  */
  {
    static const char valid_drive_letters[] =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    /* Casting away const! */
    char *dup_path = (char *)svn_path_uri_decode(path, pool);
    if (!hostname && dup_path[1] && strchr(valid_drive_letters, dup_path[1])
        && (dup_path[2] == ':' || dup_path[2] == '|')
        && dup_path[3] == '/')
      {
        /* Skip the leading slash. */
        ++dup_path;
        /* We're using path below to calculate fs_path, so keep it in sync. */
        ++path;
        if (dup_path[1] == '|')
          dup_path[1] = ':';
      }
    if (hostname)
      /* We still know that the path starts with a slash. */
      repos_root = apr_pstrcat(pool, "//", hostname, path, NULL);
    else
      repos_root = dup_path;
  }
#else
  /* Currently, the only hostnames we are allowing on non-Win32 platforms
     are the empty string and 'localhost'. */
  if (hostname)
    return svn_error_createf
      (SVN_ERR_RA_ILLEGAL_URL, NULL,
       _("Local URL '%s' contains unsupported hostname"), URL);

  repos_root = svn_path_uri_decode(path, pool);
#endif

  /* Search for a repository in the full path. */
  repos_root = svn_repos_find_root_path(repos_root, pool);
  if (!repos_root)
    return svn_error_createf
      (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, NULL,
       _("Unable to open repository '%s'"), URL);

  /* Attempt to open a repository at URL. */
  err = svn_repos_open(repos, repos_root, pool);
  if (err)
    return svn_error_createf
      (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, err,
       _("Unable to open repository '%s'"), URL);

  /* Assert capabilities directly, since client == server. */
  {
    apr_array_header_t *caps = apr_array_make(pool, 1, sizeof(const char *));
    APR_ARRAY_PUSH(caps, const char *) = SVN_RA_CAPABILITY_MERGEINFO;
    SVN_ERR(svn_repos_remember_client_capabilities(*repos, caps));
  }

  /* What remains of URL after being hacked at in the previous step is
     REPOS_URL.  FS_PATH is what we've hacked off in the process.
     Note that path is not encoded and what we gave to svn_root_find_root_path
     may have been destroyed by that function.  So we have to decode it once
     more.  But then, it is ours...
     We want the suffix of path after the repos root part.  Note that
     repos_root may contain //hostname, but path doesn't.  */
  *fs_path = svn_path_uri_decode(path, pool)
    + (strlen(repos_root)
       - (hostname ? strlen(hostname) + 2 : 0));

  /* Ensure that *FS_PATH has its leading slash. */
  if (**fs_path != '/')
    *fs_path = apr_pstrcat(pool, "/", *fs_path, NULL);

  /* Remove the path components in *fs_path from the original URL, to get
     the URL to the repository root. */
  urlbuf = svn_stringbuf_create(URL, pool);
  svn_path_remove_components(urlbuf,
                             svn_path_component_count(*fs_path));
  *repos_url = urlbuf->data;

  return SVN_NO_ERROR;
}
Exemple #13
0
svn_error_t *
svn_opt_parse_path(svn_opt_revision_t *rev,
                   const char **truepath,
                   const char *path /* UTF-8! */,
                   apr_pool_t *pool)
{
    const char *peg_rev;

    SVN_ERR(svn_opt__split_arg_at_peg_revision(truepath, &peg_rev, path, pool));

    /* Parse the peg revision, if one was found */
    if (strlen(peg_rev))
    {
        int ret;
        svn_opt_revision_t start_revision, end_revision;

        end_revision.kind = svn_opt_revision_unspecified;

        if (peg_rev[1] == '\0')  /* looking at empty peg revision */
        {
            ret = 0;
            start_revision.kind = svn_opt_revision_unspecified;
        }
        else  /* looking at non-empty peg revision */
        {
            const char *rev_str = &peg_rev[1];

            /* URLs get treated differently from wc paths. */
            if (svn_path_is_url(path))
            {
                /* URLs are URI-encoded, so we look for dates with
                   URI-encoded delimeters.  */
                int rev_len = strlen(rev_str);
                if (rev_len > 6
                        && rev_str[0] == '%'
                        && rev_str[1] == '7'
                        && (rev_str[2] == 'B'
                            || rev_str[2] == 'b')
                        && rev_str[rev_len-3] == '%'
                        && rev_str[rev_len-2] == '7'
                        && (rev_str[rev_len-1] == 'D'
                            || rev_str[rev_len-1] == 'd'))
                {
                    rev_str = svn_path_uri_decode(rev_str, pool);
                }
            }
            ret = svn_opt_parse_revision(&start_revision,
                                         &end_revision,
                                         rev_str, pool);
        }

        if (ret || end_revision.kind != svn_opt_revision_unspecified)
            return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                     _("Syntax error parsing revision '%s'"),
                                     &peg_rev[1]);

        rev->kind = start_revision.kind;
        rev->value = start_revision.value;
    }
    else
    {
        /* Didn't find a peg revision. */
        rev->kind = svn_opt_revision_unspecified;
    }

    return SVN_NO_ERROR;
}
Exemple #14
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__export(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;
  const char *from, *to;
  apr_array_header_t *targets;
  svn_error_t *err;
  svn_opt_revision_t peg_revision;
  const char *truefrom;

  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                      opt_state->targets,
                                                      ctx, pool));

  /* We want exactly 1 or 2 targets for this subcommand. */
  if (targets->nelts < 1)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
  if (targets->nelts > 2)
    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);

  /* The first target is the `from' path. */
  from = APR_ARRAY_IDX(targets, 0, const char *);

  /* Get the peg revision if present. */
  SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool));

  /* If only one target was given, split off the basename to use as
     the `to' path.  Else, a `to' path was supplied. */
  if (targets->nelts == 1)
    to = svn_path_uri_decode(svn_path_basename(truefrom, pool), pool);
  else
    to = APR_ARRAY_IDX(targets, 1, const char *);

  SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, NULL, to, pool));

  if (! opt_state->quiet)
    svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, TRUE,
                         FALSE, pool);

  if (opt_state->depth == svn_depth_unknown)
    opt_state->depth = svn_depth_infinity;

  /* Decode the partially encoded URL and escape all URL unsafe characters. */
  if (svn_path_is_url(truefrom))
    truefrom = svn_path_uri_encode(svn_path_uri_decode(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;
}
Exemple #15
0
static svn_error_t *
make_reporter(svn_ra_session_t *session,
              const svn_ra_reporter3_t **reporter,
              void **report_baton,
              svn_revnum_t revision,
              const char *target,
              const char *other_url,
              svn_boolean_t text_deltas,
              svn_depth_t depth,
              svn_boolean_t send_copyfrom_args,
              svn_boolean_t ignore_ancestry,
              const svn_delta_editor_t *editor,
              void *edit_baton,
              apr_pool_t *pool)
{
  svn_ra_local__session_baton_t *sess = session->priv;
  void *rbaton;
  int repos_url_len;
  const char *other_fs_path = NULL;
  const char *repos_url_decoded;

  /* Get the HEAD revision if one is not supplied. */
  if (! SVN_IS_VALID_REVNUM(revision))
    SVN_ERR(svn_fs_youngest_rev(&revision, sess->fs, pool));

  /* If OTHER_URL was provided, validate it and convert it into a
     regular filesystem path. */
  if (other_url)
    {
      other_url = svn_path_uri_decode(other_url, pool);
      repos_url_decoded = svn_path_uri_decode(sess->repos_url, pool);
      repos_url_len = strlen(repos_url_decoded);

      /* Sanity check:  the other_url better be in the same repository as
         the original session url! */
      if (strncmp(other_url, repos_url_decoded, repos_url_len) != 0)
        return svn_error_createf
          (SVN_ERR_RA_ILLEGAL_URL, NULL,
           _("'%s'\n"
             "is not the same repository as\n"
             "'%s'"), other_url, sess->repos_url);

      other_fs_path = other_url + repos_url_len;
    }

  /* Pass back our reporter */
  *reporter = &ra_local_reporter;

  SVN_ERR(get_username(session, pool));

  if (sess->callbacks)
    SVN_ERR(svn_delta_get_cancellation_editor(sess->callbacks->cancel_func,
                                              sess->callback_baton,
                                              editor,
                                              edit_baton,
                                              &editor,
                                              &edit_baton,
                                              pool));

  /* Build a reporter baton. */
  SVN_ERR(svn_repos_begin_report2(&rbaton,
                                  revision,
                                  sess->repos,
                                  sess->fs_path->data,
                                  target,
                                  other_fs_path,
                                  text_deltas,
                                  depth,
                                  ignore_ancestry,
                                  send_copyfrom_args,
                                  editor,
                                  edit_baton,
                                  NULL,
                                  NULL,
                                  pool));

  /* Wrap the report baton given us by the repos layer with our own
     reporter baton. */
  *report_baton = make_reporter_baton(sess, rbaton, pool);

  return SVN_NO_ERROR;
}
Exemple #16
0
svn_error_t *
svn_opt_parse_path(svn_opt_revision_t *rev,
                   const char **truepath,
                   const char *path /* UTF-8! */,
                   apr_pool_t *pool)
{
  const char *peg_rev;

  SVN_ERR(svn_opt__split_arg_at_peg_revision(truepath, &peg_rev, path, pool));

  /* Parse the peg revision, if one was found */
  if (strlen(peg_rev))
    {
      int ret;
      svn_opt_revision_t start_revision, end_revision;

      end_revision.kind = svn_opt_revision_unspecified;

      if (peg_rev[1] == '\0')  /* looking at empty peg revision */
        {
          ret = 0;
          start_revision.kind = svn_opt_revision_unspecified;
          start_revision.value.number = 0;
        }
      else  /* looking at non-empty peg revision */
        {
          const char *rev_str = &peg_rev[1];

          /* URLs get treated differently from wc paths. */
          if (svn_path_is_url(path))
            {
              /* URLs are URI-encoded, so we look for dates with
                 URI-encoded delimeters.  */
              size_t rev_len = strlen(rev_str);
              if (rev_len > 6
                  && rev_str[0] == '%'
                  && rev_str[1] == '7'
                  && (rev_str[2] == 'B'
                      || rev_str[2] == 'b')
                  && rev_str[rev_len-3] == '%'
                  && rev_str[rev_len-2] == '7'
                  && (rev_str[rev_len-1] == 'D'
                      || rev_str[rev_len-1] == 'd'))
                {
                  rev_str = svn_path_uri_decode(rev_str, pool);
                }
            }
          ret = svn_opt_parse_revision(&start_revision,
                                       &end_revision,
                                       rev_str, pool);
        }

      if (ret || end_revision.kind != svn_opt_revision_unspecified)
        {
          /* If an svn+ssh URL was used and it contains only one @,
           * provide an error message that presents a possible solution
           * to the parsing error (issue #2349). */
          if (strncmp(path, "svn+ssh://", 10) == 0)
            {
              const char *at;

              at = strchr(path, '@');
              if (at && strrchr(path, '@') == at)
                return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                         _("Syntax error parsing peg revision "
                                           "'%s'; did you mean '%s@'?"),
                                       &peg_rev[1], path);
            }

          return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                   _("Syntax error parsing peg revision '%s'"),
                                   &peg_rev[1]);
        }
      rev->kind = start_revision.kind;
      rev->value = start_revision.value;
    }
  else
    {
      /* Didn't find a peg revision. */
      rev->kind = svn_opt_revision_unspecified;
    }

  return SVN_NO_ERROR;
}
Exemple #17
0
svn_error_t *svn_ra_neon__get_baseline_props(svn_string_t *bc_relative,
                                             svn_ra_neon__resource_t **bln_rsrc,
                                             svn_ra_neon__session_t *sess,
                                             const char *url,
                                             svn_revnum_t revision,
                                             const ne_propname *which_props,
                                             apr_pool_t *pool)
{
  svn_ra_neon__resource_t *rsrc;
  const char *vcc;
  const svn_string_t *relative_path;
  const char *my_bc_relative;
  const char *lopped_path;

  /* ### we may be able to replace some/all of this code with an
     ### expand-property REPORT when that is available on the server. */

  /* -------------------------------------------------------------------
     STEP 1

     Fetch the following properties from the given URL (or, if URL no
     longer exists in HEAD, get the properties from the nearest
     still-existing parent resource):

     *) DAV:version-controlled-configuration so that we can reach the
        baseline information.

     *) svn:baseline-relative-path so that we can find this resource
        within a Baseline Collection.  If we need to search up parent
        directories, then the relative path is this property value
        *plus* any trailing components we had to chop off.

     *) DAV:resourcetype so that we can identify whether this resource
        is a collection or not -- assuming we never had to search up
        parent directories.
  */

  SVN_ERR(svn_ra_neon__search_for_starting_props(&rsrc, &lopped_path,
                                                 sess, url, pool));

  SVN_ERR(svn_ra_neon__get_vcc(&vcc, sess, url, pool));
  if (vcc == NULL)
    {
      /* ### better error reporting... */

      /* ### need an SVN_ERR here */
      return svn_error_create(APR_EGENERAL, NULL,
                              _("The VCC property was not found on the "
                                "resource"));
    }

  /* Allocate our own bc_relative path. */
  relative_path = apr_hash_get(rsrc->propset,
                               SVN_RA_NEON__PROP_BASELINE_RELPATH,
                               APR_HASH_KEY_STRING);
  if (relative_path == NULL)
    {
      /* ### better error reporting... */
      /* ### need an SVN_ERR here */
      return svn_error_create(APR_EGENERAL, NULL,
                              _("The relative-path property was not "
                                "found on the resource"));
    }

  /* don't forget to tack on the parts we lopped off in order to find
     the VCC...  We are expected to return a URI decoded relative
     path, so decode the lopped path first. */
  my_bc_relative = svn_path_join(relative_path->data,
                                 svn_path_uri_decode(lopped_path, pool),
                                 pool);

  /* if they want the relative path (could be, they're just trying to find
     the baseline collection), then return it */
  if (bc_relative)
    {
      bc_relative->data = my_bc_relative;
      bc_relative->len = strlen(my_bc_relative);
    }

  /* -------------------------------------------------------------------
     STEP 2

     We have the Version Controlled Configuration (VCC). From here, we
     need to reach the Baseline for specified revision.

     If the revision is SVN_INVALID_REVNUM, then we're talking about
     the HEAD revision. We have one extra step to reach the Baseline:

     *) Fetch the DAV:checked-in from the VCC; it points to the Baseline.

     If we have a specific revision, then we use a Label header when
     fetching props from the VCC. This will direct us to the Baseline
     with that label (in this case, the label == the revision number).

     From the Baseline, we fetch the following properties:

     *) DAV:baseline-collection, which is a complete tree of the Baseline
        (in SVN terms, this tree is rooted at a specific revision)

     *) DAV:version-name to get the revision of the Baseline that we are
        querying. When asking about the HEAD, this tells us its revision.
  */

  if (revision == SVN_INVALID_REVNUM)
    {
      /* Fetch the latest revision */

      const svn_string_t *baseline;

      /* Get the Baseline from the DAV:checked-in value, then fetch its
         DAV:baseline-collection property. */
      /* ### should wrap this with info about rsrc==VCC */
      SVN_ERR(svn_ra_neon__get_one_prop(&baseline, sess, vcc, NULL,
                                        &svn_ra_neon__checked_in_prop, pool));

      /* ### do we want to optimize the props we fetch, based on what the
         ### user asked for? i.e. omit version-name if latest_rev is NULL */
      SVN_ERR(svn_ra_neon__get_props_resource(&rsrc, sess,
                                              baseline->data, NULL,
                                              which_props, pool));
    }
  else
    {
      /* Fetch a specific revision */

      char label[20];

      /* ### send Label hdr, get DAV:baseline-collection [from the baseline] */

      apr_snprintf(label, sizeof(label), "%ld", revision);

      /* ### do we want to optimize the props we fetch, based on what the
         ### user asked for? i.e. omit version-name if latest_rev is NULL */
      SVN_ERR(svn_ra_neon__get_props_resource(&rsrc, sess, vcc, label,
                                              which_props, pool));
    }

  /* Return the baseline rsrc, which now contains whatever set of
     props the caller wanted. */
  *bln_rsrc = rsrc;
  return SVN_NO_ERROR;
}