Пример #1
0
svn_error_t * svn_ra_neon__get_props(apr_hash_t **results,
                                     svn_ra_neon__session_t *sess,
                                     const char *url,
                                     int depth,
                                     const char *label,
                                     const ne_propname *which_props,
                                     apr_pool_t *pool)
{
  propfind_ctx_t pc;
  svn_stringbuf_t *body;
  apr_hash_t *extra_headers = apr_hash_make(pool);

  svn_ra_neon__add_depth_header(extra_headers, depth);

  /* If we have a label, use it. */
  if (label != NULL)
    apr_hash_set(extra_headers, "Label", 5, label);

  /* It's easier to roll our own PROPFIND here than use neon's current
     interfaces. */
  /* The start of the request body is fixed: */
  body = svn_stringbuf_create
    ("<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
     "<propfind xmlns=\"DAV:\">" DEBUG_CR, pool);

  /* Are we asking for specific propert(y/ies), or just all of them? */
  if (which_props)
    {
      int n;
      apr_pool_t *iterpool = svn_pool_create(pool);

      svn_stringbuf_appendcstr(body, "<prop>" DEBUG_CR);
      for (n = 0; which_props[n].name != NULL; n++)
        {
          svn_pool_clear(iterpool);
          svn_stringbuf_appendcstr
            (body, apr_pstrcat(iterpool, "<", which_props[n].name, " xmlns=\"",
                               which_props[n].nspace, "\"/>" DEBUG_CR, NULL));
        }
      svn_stringbuf_appendcstr(body, "</prop></propfind>" DEBUG_CR);
      svn_pool_destroy(iterpool);
    }
  else
    {
      svn_stringbuf_appendcstr(body, "<allprop/></propfind>" DEBUG_CR);
    }

  /* Initialize our baton. */
  memset(&pc, 0, sizeof(pc));
  pc.pool = pool;
  pc.propbuffer = apr_hash_make(pool);
  pc.props = apr_hash_make(pool);
  pc.cdata = svn_stringbuf_create("", pool);

  /* Create and dispatch the request! */
  SVN_ERR(svn_ra_neon__parsed_request(sess, "PROPFIND", url,
                                      body->data, 0,
                                      set_parser,
                                      start_element,
                                      svn_ra_neon__xml_collect_cdata,
                                      end_element,
                                      &pc, extra_headers, NULL, FALSE, pool));

  *results = pc.props;
  return SVN_NO_ERROR;
}
Пример #2
0
/* Copy the versioned dir SRC_ABSPATH in DB to the path DST_ABSPATH in DB,
   recursively.  If METADATA_ONLY is true, copy only the versioned metadata,
   otherwise copy both the versioned metadata and the filesystem nodes (even
   if they are the wrong kind, and including unversioned children).
   If IS_MOVE is true, record move information in working copy meta
   data in addition to copying the directory.

   WITHIN_ONE_WC is TRUE if the copy/move is within a single working copy (root)
 */
static svn_error_t *
copy_versioned_dir(svn_wc__db_t *db,
                   const char *src_abspath,
                   const char *dst_abspath,
                   const char *dst_op_root_abspath,
                   const char *tmpdir_abspath,
                   svn_boolean_t metadata_only,
                   svn_boolean_t is_move,
                   svn_cancel_func_t cancel_func,
                   void *cancel_baton,
                   svn_wc_notify_func2_t notify_func,
                   void *notify_baton,
                   apr_pool_t *scratch_pool)
{
  svn_skel_t *work_items = NULL;
  const char *dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
  apr_hash_t *versioned_children;
  apr_hash_t *conflicted_children;
  apr_hash_t *disk_children;
  apr_hash_index_t *hi;
  svn_node_kind_t disk_kind;
  apr_pool_t *iterpool;

  /* Prepare a temp copy of the single filesystem node (usually a dir). */
  if (!metadata_only)
    {
      SVN_ERR(copy_to_tmpdir(&work_items, &disk_kind,
                             db, src_abspath, dst_abspath,
                             tmpdir_abspath,
                             FALSE /* file_copy */,
                             FALSE /* unversioned */,
                             cancel_func, cancel_baton,
                             scratch_pool, scratch_pool));
    }

  /* Copy the (single) node's metadata, and move the new filesystem node
     into place. */
  SVN_ERR(svn_wc__db_op_copy(db, src_abspath, dst_abspath,
                             dst_op_root_abspath, is_move, work_items,
                             scratch_pool));

  if (notify_func)
    {
      svn_wc_notify_t *notify
        = svn_wc_create_notify(dst_abspath, svn_wc_notify_add,
                               scratch_pool);
      notify->kind = svn_node_dir;

      /* When we notify that we performed a copy, make sure we already did */
      if (work_items != NULL)
        SVN_ERR(svn_wc__wq_run(db, dir_abspath,
                               cancel_func, cancel_baton, scratch_pool));

      (*notify_func)(notify_baton, notify, scratch_pool);
    }

  if (!metadata_only && disk_kind == svn_node_dir)
    /* All filesystem children, versioned and unversioned.  We're only
       interested in their names, so we can pass TRUE as the only_check_type
       param. */
    SVN_ERR(svn_io_get_dirents3(&disk_children, src_abspath, TRUE,
                                scratch_pool, scratch_pool));
  else
    disk_children = NULL;

  /* Copy all the versioned children */
  iterpool = svn_pool_create(scratch_pool);
  SVN_ERR(svn_wc__db_read_children_info(&versioned_children,
                                        &conflicted_children,
                                        db, src_abspath,
                                        scratch_pool, iterpool));
  for (hi = apr_hash_first(scratch_pool, versioned_children);
       hi;
       hi = apr_hash_next(hi))
    {
      const char *child_name, *child_src_abspath, *child_dst_abspath;
      struct svn_wc__db_info_t *info;

      svn_pool_clear(iterpool);

      if (cancel_func)
        SVN_ERR(cancel_func(cancel_baton));

      child_name = svn__apr_hash_index_key(hi);
      info = svn__apr_hash_index_val(hi);
      child_src_abspath = svn_dirent_join(src_abspath, child_name, iterpool);
      child_dst_abspath = svn_dirent_join(dst_abspath, child_name, iterpool);

      if (info->op_root)
        SVN_ERR(svn_wc__db_op_copy_shadowed_layer(db,
                                                  child_src_abspath,
                                                  child_dst_abspath,
                                                  is_move,
                                                  scratch_pool));

      if (info->status == svn_wc__db_status_normal
          || info->status == svn_wc__db_status_added)
        {
          /* We have more work to do than just changing the DB */
          if (info->kind == svn_node_file)
            {
              /* We should skip this node if this child is a file external
                 (issues #3589, #4000) */
              if (!info->file_external)
                SVN_ERR(copy_versioned_file(db,
                                            child_src_abspath,
                                            child_dst_abspath,
                                            dst_op_root_abspath,
                                            tmpdir_abspath,
                                            metadata_only, info->conflicted,
                                            is_move,
                                            cancel_func, cancel_baton,
                                            NULL, NULL,
                                            iterpool));
            }
          else if (info->kind == svn_node_dir)
            SVN_ERR(copy_versioned_dir(db,
                                       child_src_abspath, child_dst_abspath,
                                       dst_op_root_abspath, tmpdir_abspath,
                                       metadata_only, is_move,
                                       cancel_func, cancel_baton, NULL, NULL,
                                       iterpool));
          else
            return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                                     _("cannot handle node kind for '%s'"),
                                     svn_dirent_local_style(child_src_abspath,
                                                            scratch_pool));
        }
      else if (info->status == svn_wc__db_status_deleted
          || info->status == svn_wc__db_status_not_present
          || info->status == svn_wc__db_status_excluded)
        {
          /* This will be copied as some kind of deletion. Don't touch
             any actual files */
          SVN_ERR(svn_wc__db_op_copy(db, child_src_abspath,
                                     child_dst_abspath, dst_op_root_abspath,
                                     is_move, NULL, iterpool));

          /* Don't recurse on children while all we do is creating not-present
             children */
        }
      else if (info->status == svn_wc__db_status_incomplete)
        {
          /* Should go ahead and copy incomplete to incomplete? Try to
             copy as much as possible, or give up early? */
          return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
                                   _("Cannot handle status of '%s'"),
                                   svn_dirent_local_style(child_src_abspath,
                                                          iterpool));
        }
      else
        {
          SVN_ERR_ASSERT(info->status == svn_wc__db_status_server_excluded);

          return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
                                   _("Cannot copy '%s' excluded by server"),
                                   svn_dirent_local_style(child_src_abspath,
                                                          iterpool));
        }

      if (disk_children
          && (info->status == svn_wc__db_status_normal
              || info->status == svn_wc__db_status_added))
        {
          /* Remove versioned child as it has been handled */
          svn_hash_sets(disk_children, child_name, NULL);
        }
    }

  /* Copy the remaining filesystem children, which are unversioned, skipping
     any conflict-marker files. */
  if (disk_children && apr_hash_count(disk_children))
    {
      apr_hash_t *marker_files;

      SVN_ERR(svn_wc__db_get_conflict_marker_files(&marker_files, db,
                                                   src_abspath, scratch_pool,
                                                   scratch_pool));

      work_items = NULL;

      for (hi = apr_hash_first(scratch_pool, disk_children); hi;
           hi = apr_hash_next(hi))
        {
          const char *name = svn__apr_hash_index_key(hi);
          const char *unver_src_abspath, *unver_dst_abspath;
          svn_skel_t *work_item;

          if (svn_wc_is_adm_dir(name, iterpool))
            continue;

          if (cancel_func)
            SVN_ERR(cancel_func(cancel_baton));

          svn_pool_clear(iterpool);
          unver_src_abspath = svn_dirent_join(src_abspath, name, iterpool);
          unver_dst_abspath = svn_dirent_join(dst_abspath, name, iterpool);

          if (marker_files &&
              svn_hash_gets(marker_files, unver_src_abspath))
            continue;

          SVN_ERR(copy_to_tmpdir(&work_item, NULL, db, unver_src_abspath,
                                 unver_dst_abspath, tmpdir_abspath,
                                 TRUE /* recursive */, TRUE /* unversioned */,
                                 cancel_func, cancel_baton,
                                 scratch_pool, iterpool));

          if (work_item)
            work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
        }
      SVN_ERR(svn_wc__db_wq_add(db, dst_abspath, work_items, iterpool));
    }

  svn_pool_destroy(iterpool);

  return SVN_NO_ERROR;
}
Пример #3
0
svn_error_t *
svn_wc__delete_many(svn_wc_context_t *wc_ctx,
                    const apr_array_header_t *targets,
                    svn_boolean_t keep_local,
                    svn_boolean_t delete_unversioned_target,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    svn_wc_notify_func2_t notify_func,
                    void *notify_baton,
                    apr_pool_t *scratch_pool)
{
  svn_wc__db_t *db = wc_ctx->db;
  svn_error_t *err;
  svn_wc__db_status_t status;
  svn_node_kind_t kind;
  svn_skel_t *work_items = NULL;
  apr_array_header_t *versioned_targets;
  const char *local_abspath;
  int i;
  apr_pool_t *iterpool;

  iterpool = svn_pool_create(scratch_pool);
  versioned_targets = apr_array_make(scratch_pool, targets->nelts,
                                     sizeof(const char *));
  for (i = 0; i < targets->nelts; i++)
    {
      svn_boolean_t conflicted = FALSE;
      const char *repos_relpath;

      svn_pool_clear(iterpool);

      local_abspath = APR_ARRAY_IDX(targets, i, const char *);
      err = svn_wc__db_read_info(&status, &kind, NULL, &repos_relpath, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                 NULL, &conflicted,
                                 NULL, NULL, NULL, NULL, NULL, NULL,
                                 db, local_abspath, iterpool, iterpool);

      if (err)
        {
          if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
            {
              svn_error_clear(err);
              if (delete_unversioned_target && !keep_local)
                SVN_ERR(erase_unversioned_from_wc(local_abspath, FALSE,
                                                  cancel_func, cancel_baton,
                                                  iterpool));
              continue;
            }
         else
          return svn_error_trace(err);
        }

      APR_ARRAY_PUSH(versioned_targets, const char *) = local_abspath;

      switch (status)
        {
          /* svn_wc__db_status_server_excluded handled by
           * svn_wc__db_op_delete_many */
          case svn_wc__db_status_excluded:
          case svn_wc__db_status_not_present:
            return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                                     _("'%s' cannot be deleted"),
                                     svn_dirent_local_style(local_abspath,
                                                            iterpool));

          /* Explicitly ignore other statii */
          default:
            break;
        }

      if (status == svn_wc__db_status_normal
          && kind == svn_node_dir)
        {
          svn_boolean_t is_wcroot;
          SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath,
                                       iterpool));

          if (is_wcroot)
            return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
                                     _("'%s' is the root of a working copy and "
                                       "cannot be deleted"),
                                     svn_dirent_local_style(local_abspath,
                                                            iterpool));
        }
      if (repos_relpath && !repos_relpath[0])
        return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
                                     _("'%s' represents the repository root "
                                       "and cannot be deleted"),
                                     svn_dirent_local_style(local_abspath,
                                                            iterpool));

      /* Verify if we have a write lock on the parent of this node as we might
         be changing the childlist of that directory. */
      SVN_ERR(svn_wc__write_check(db, svn_dirent_dirname(local_abspath,
                                                         iterpool),
                                  iterpool));

      /* Prepare the on-disk delete */
      if (!keep_local)
        {
          svn_skel_t *work_item;

          SVN_ERR(create_delete_wq_items(&work_item, db, local_abspath, kind,
                                         conflicted,
                                         scratch_pool, iterpool));

          work_items = svn_wc__wq_merge(work_items, work_item,
                                        scratch_pool);
        }
    }

  if (versioned_targets->nelts == 0)
    return SVN_NO_ERROR;

  SVN_ERR(svn_wc__db_op_delete_many(db, versioned_targets,
                                    !keep_local /* delete_dir_externals */,
                                    work_items,
                                    cancel_func, cancel_baton,
                                    notify_func, notify_baton,
                                    iterpool));

  if (work_items != NULL)
    {
      /* Our only caller locked the wc, so for now assume it only passed
         nodes from a single wc (asserted in svn_wc__db_op_delete_many) */
      local_abspath = APR_ARRAY_IDX(versioned_targets, 0, const char *);

      SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
                             iterpool));
    }
Пример #4
0
static svn_error_t *
test_query_expectations(apr_pool_t *scratch_pool)
{
  sqlite3 *sdb;
  int i;
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
  svn_error_t *warnings = NULL;
  svn_boolean_t supports_query_info;

  SVN_ERR(create_memory_db(&sdb, scratch_pool));

  SVN_ERR(supported_explain_query_plan(&supports_query_info, sdb,
                                       scratch_pool));
  if (!supports_query_info)
    {
      SQLITE_ERR(sqlite3_close(sdb));
      return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
                              "Sqlite doesn't support EXPLAIN QUERY PLAN");
    }

  for (i=0; i < STMT_SCHEMA_FIRST; i++)
    {
      sqlite3_stmt *stmt;
      const char *tail;
      int r;
      svn_boolean_t warned = FALSE;
      apr_array_header_t *rows = NULL;

      if (is_schema_statement(i))
        continue;

      /* Prepare statement to find if it is a single statement. */
      r = sqlite3_prepare_v2(sdb, wc_queries[i], -1, &stmt, &tail);

      if (r != SQLITE_OK)
        continue; /* Parse failure is already reported by 'test_parable' */

      SQLITE_ERR(sqlite3_finalize(stmt));
      if (tail[0] != '\0')
        continue; /* Multi-queries are currently not testable */

      svn_pool_clear(iterpool);

      r = sqlite3_prepare_v2(sdb,
                             apr_pstrcat(iterpool,
                                         "EXPLAIN QUERY PLAN ",
                                         wc_queries[i],
                                         SVN_VA_NULL),
                             -1, &stmt, &tail);

      if (r != SQLITE_OK)
        continue; /* EXPLAIN not enabled or doesn't support this query */

      while (SQLITE_ROW == (r = sqlite3_step(stmt)))
        {
          /*int iSelectid;
          int iOrder;
          int iFrom;*/
          const unsigned char *zDetail;
          char *detail;
          struct explanation_item *item;

          /* ### The following code is correct for current Sqlite versions
             ### (tested with 3.7.x), but the EXPLAIN QUERY PLAN output
             ### is not guaranteed to be stable for future versions. */

          /* Names as in Sqlite documentation */
          /*iSelectid = sqlite3_column_int(stmt, 0);
          iOrder = sqlite3_column_int(stmt, 1);
          iFrom = sqlite3_column_int(stmt, 2);*/
          zDetail = sqlite3_column_text(stmt, 3);

          if (! zDetail)
            continue;

          if (!rows)
            rows = apr_array_make(iterpool, 10, sizeof(const char*));

          detail = apr_pstrdup(iterpool, (const char*)zDetail);

          APR_ARRAY_PUSH(rows, const char *) = detail;

          SVN_ERR(parse_explanation_item(&item, detail, iterpool));

          if (!item)
            continue; /* Not parsable or not interesting */

          if (item->search
              && item->automatic_index)
            {
              warned = TRUE;
              if (!is_slow_statement(i))
                {
                  warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings,
                                "%s: "
                                "Creates a temporary index: %s\n",
                                wc_query_info[i][0], wc_queries[i]);
                }
            }
          else if (item->search && item->primary_key)
            {
              /* Nice */
            }
          else if (item->search
                   && ((item->expression_vars < 2 && is_node_table(item->table))
                       || (item->expression_vars < 1))
                   && !is_result_table(item->table))
            {
              if (in_list(primary_key_statements, i))
                {
                  /* Reported as primary key index usage in Sqlite 3.7,
                     as table scan in 3.8+, while the execution plan is
                     identical: read first record from table */
                }
              else if (!is_slow_statement(i))
                {
                  warned = TRUE;
                  warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings,
                                "%s: "
                                "Uses %s with only %d index component: (%s)\n%s",
                                wc_query_info[i][0], item->table,
                                item->expression_vars, item->expressions,
                                wc_queries[i]);
                }
              else
                warned = TRUE;
            }
          else if (item->search && !item->index)
            {
              warned = TRUE;
              if (!is_slow_statement(i))
                warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings,
                                "%s: "
                                "Query on %s doesn't use an index:\n%s",
                                wc_query_info[i][0], item->table, wc_queries[i]);
            }
          else if (item->scan && !is_result_table(item->table))
            {
              warned = TRUE;
              if (!is_slow_statement(i))
                warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings,
                                "Query %s: "
                                "Performs scan on %s:\n%s",
                                wc_query_info[i][0], item->table, wc_queries[i]);
            }
          else if (item->create_btree)
            {
              warned = TRUE;
              if (!is_slow_statement(i))
                warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings,
                                "Query %s: Creates a temporary B-TREE:\n%s",
                                wc_query_info[i][0], wc_queries[i]);
            }
        }
      SQLITE_ERR(sqlite3_reset(stmt));
      SQLITE_ERR(sqlite3_finalize(stmt));

      if (!warned && is_slow_statement(i))
        {
          printf("DBG: Expected %s to be reported as slow, but it wasn't\n",
                 wc_query_info[i][0]);
        }

      if (rows && warned != is_slow_statement(i))
        {
          int w;
          svn_error_t *info = NULL;
          for (w = rows->nelts-1; w >= 0; w--)
            {
              if (warned)
                info = svn_error_createf(SVN_ERR_SQLITE_CONSTRAINT, info,
                                         "|%s", APR_ARRAY_IDX(rows, w,
                                                              const char*));
              else
                printf("|%s\n", APR_ARRAY_IDX(rows, w, const char*));
            }

          warnings = svn_error_compose_create(warnings, info);
        }
Пример #5
0
/* Edit CHUNK and return the result in *MERGED_CHUNK allocated in POOL. */
static svn_error_t *
edit_chunk(apr_array_header_t **merged_chunk,
           apr_array_header_t *chunk,
           const char *editor_cmd,
           apr_hash_t *config,
           apr_pool_t *result_pool,
           apr_pool_t *scratch_pool)
{
  apr_file_t *temp_file;
  const char *temp_file_name;
  int i;
  apr_off_t pos;
  svn_boolean_t eof;
  svn_error_t *err;
  apr_pool_t *iterpool;

  SVN_ERR(svn_io_open_unique_file3(&temp_file, &temp_file_name, NULL,
                                   svn_io_file_del_on_pool_cleanup,
                                   scratch_pool, scratch_pool));
  iterpool = svn_pool_create(scratch_pool);
  for (i = 0; i < chunk->nelts; i++)
    {
      svn_stringbuf_t *line = APR_ARRAY_IDX(chunk, i, svn_stringbuf_t *);
      apr_size_t bytes_written;

      svn_pool_clear(iterpool);

      SVN_ERR(svn_io_file_write_full(temp_file, line->data, line->len,
                                     &bytes_written, iterpool));
      if (line->len != bytes_written)
        return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL,
                                _("Could not write data to temporary file"));
    }
  SVN_ERR(svn_io_file_flush(temp_file, scratch_pool));

  err = svn_cmdline__edit_file_externally(temp_file_name, editor_cmd,
                                          config, scratch_pool);
  if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
    {
      svn_error_t *root_err = svn_error_root_cause(err);

      SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n",
                                  root_err->message ? root_err->message :
                                  _("No editor found.")));
      svn_error_clear(err);
      *merged_chunk = NULL;
      svn_pool_destroy(iterpool);
      return SVN_NO_ERROR;
    }
  else if (err && (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
    {
      svn_error_t *root_err = svn_error_root_cause(err);

      SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n",
                                  root_err->message ? root_err->message :
                                  _("Error running editor.")));
      svn_error_clear(err);
      *merged_chunk = NULL;
      svn_pool_destroy(iterpool);
      return SVN_NO_ERROR;
    }
  else if (err)
    return svn_error_trace(err);

  *merged_chunk = apr_array_make(result_pool, 1, sizeof(svn_stringbuf_t *));
  pos = 0;
  SVN_ERR(svn_io_file_seek(temp_file, APR_SET, &pos, scratch_pool));
  do
    {
      svn_stringbuf_t *line;
      const char *eol_str;

      svn_pool_clear(iterpool);

      SVN_ERR(svn_io_file_readline(temp_file, &line, &eol_str, &eof,
                                   APR_SIZE_MAX, result_pool, iterpool));
      if (eol_str)
        svn_stringbuf_appendcstr(line, eol_str);

      APR_ARRAY_PUSH(*merged_chunk, svn_stringbuf_t *) = line;
    }
  while (!eof);
  svn_pool_destroy(iterpool);

  SVN_ERR(svn_io_file_close(temp_file, scratch_pool));

  return SVN_NO_ERROR;
}
/* This implements the `svn_ra_neon__endelm_cb_t' prototype. */
static svn_error_t *
getlocks_end_element(void *userdata, int state,
                     const char *ns, const char *ln)
{
  get_locks_baton_t *baton = userdata;
  const svn_ra_neon__xml_elm_t *elm;

  elm = svn_ra_neon__lookup_xml_elem(getlocks_report_elements, ns, ln);

  /* Just skip unknown elements. */
  if (elm == NULL)
    return SVN_NO_ERROR;

  switch (elm->id)
    {
    case ELEM_lock:
      /* is the final svn_lock_t valid?  all fields must be present
         except for 'comment' and 'expiration_date'. */
      if ((! baton->current_lock->path)
          || (! baton->current_lock->token)
          || (! baton->current_lock->owner)
          || (! baton->current_lock->creation_date))
        SVN_ERR(svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                                 _("Incomplete lock data returned")));

      /* Filter out unwanted paths.  Since Subversion only allows
         locks on files, we can treat depth=immediates the same as
         depth=files for filtering purposes.  Meaning, we'll keep
         this lock if:

         a) its path is the very path we queried, or
         b) we've asked for a fully recursive answer, or
         c) we've asked for depth=files or depth=immediates, and this
            lock is on an immediate child of our query path.
      */
      if ((strcmp(baton->path, baton->current_lock->path) == 0)
          || (baton->requested_depth == svn_depth_infinity))
        {
          apr_hash_set(baton->lock_hash, baton->current_lock->path,
                       APR_HASH_KEY_STRING, baton->current_lock);
        }
      else if ((baton->requested_depth == svn_depth_files) ||
               (baton->requested_depth == svn_depth_immediates))
        {
          const char *rel_uri = svn_fspath__is_child(baton->path,
                                                     baton->current_lock->path,
                                                     baton->scratchpool);
          if (rel_uri && (svn_path_component_count(rel_uri) == 1))
            apr_hash_set(baton->lock_hash, baton->current_lock->path,
                         APR_HASH_KEY_STRING, baton->current_lock);
          svn_pool_clear(baton->scratchpool);
        }
      break;

    case ELEM_lock_path:
      /* neon has already xml-unescaped the cdata for us. */
      baton->current_lock->path =
        svn_fspath__canonicalize(apr_pstrmemdup(baton->scratchpool,
                                                baton->cdata_accum->data,
                                                baton->cdata_accum->len),
                                 baton->pool);

      /* clean up the accumulator. */
      svn_stringbuf_setempty(baton->cdata_accum);
      svn_pool_clear(baton->scratchpool);
      break;

    case ELEM_lock_token:
      /* neon has already xml-unescaped the cdata for us. */
      baton->current_lock->token = apr_pstrmemdup(baton->pool,
                                                  baton->cdata_accum->data,
                                                  baton->cdata_accum->len);
      /* clean up the accumulator. */
      svn_stringbuf_setempty(baton->cdata_accum);
      svn_pool_clear(baton->scratchpool);
      break;

    case ELEM_lock_creationdate:
      SVN_ERR(svn_time_from_cstring(&(baton->current_lock->creation_date),
                                    baton->cdata_accum->data,
                                    baton->scratchpool));
      /* clean up the accumulator. */
      svn_stringbuf_setempty(baton->cdata_accum);
      svn_pool_clear(baton->scratchpool);
      break;

    case ELEM_lock_expirationdate:
      SVN_ERR(svn_time_from_cstring(&(baton->current_lock->expiration_date),
                                    baton->cdata_accum->data,
                                    baton->scratchpool));
      /* clean up the accumulator. */
      svn_stringbuf_setempty(baton->cdata_accum);
      svn_pool_clear(baton->scratchpool);
      break;

    case ELEM_lock_owner:
    case ELEM_lock_comment:
      {
        const char *final_val;

        if (baton->encoding)
          {
            /* Possibly recognize other encodings someday. */
            if (strcmp(baton->encoding, "base64") == 0)
              {
                svn_string_t *encoded_val;
                const svn_string_t *decoded_val;

                encoded_val = svn_string_create_from_buf(baton->cdata_accum,
                                                         baton->scratchpool);
                decoded_val = svn_base64_decode_string(encoded_val,
                                                       baton->scratchpool);
                final_val = decoded_val->data;
              }
            else
              return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
                                       NULL,
                                       _("Got unrecognized encoding '%s'"),
                                       baton->encoding);

            baton->encoding = NULL;
          }
        else
          {
            /* neon has already xml-unescaped the cdata for us. */
            final_val = baton->cdata_accum->data;
          }

        if (elm->id == ELEM_lock_owner)
          baton->current_lock->owner = apr_pstrdup(baton->pool, final_val);
        if (elm->id == ELEM_lock_comment)
          baton->current_lock->comment = apr_pstrdup(baton->pool, final_val);

        /* clean up the accumulator. */
        svn_stringbuf_setempty(baton->cdata_accum);
        svn_pool_clear(baton->scratchpool);
        break;
      }


    default:
      break;
    }

  return SVN_NO_ERROR;
}
Пример #7
0
/* Public Interface */
svn_error_t *
svn_wc_diff6(svn_wc_context_t *wc_ctx,
             const char *local_abspath,
             const svn_wc_diff_callbacks4_t *callbacks,
             void *callback_baton,
             svn_depth_t depth,
             svn_boolean_t ignore_ancestry,
             svn_boolean_t show_copies_as_adds,
             svn_boolean_t use_git_diff_format,
             const apr_array_header_t *changelist_filter,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
             apr_pool_t *scratch_pool)
{
  struct diff_baton eb = { 0 };
  svn_node_kind_t kind;
  svn_boolean_t get_all;
  const svn_diff_tree_processor_t *processor;

  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
  SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
                               FALSE /* allow_missing */,
                               TRUE /* show_deleted */,
                               FALSE /* show_hidden */,
                               scratch_pool));

  if (kind == svn_node_dir)
    eb.anchor_abspath = local_abspath;
  else
    eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);

  SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
                                      callbacks, callback_baton, TRUE,
                                      scratch_pool, scratch_pool));

  if (use_git_diff_format)
    show_copies_as_adds = TRUE;
  if (show_copies_as_adds)
    ignore_ancestry = FALSE;



  /*
  if (reverse_order)
    processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
   */

  if (! show_copies_as_adds && !use_git_diff_format)
    processor = svn_diff__tree_processor_copy_as_changed_create(processor,
                                                                scratch_pool);

  eb.db = wc_ctx->db;
  eb.processor = processor;
  eb.ignore_ancestry = ignore_ancestry;
  eb.show_copies_as_adds = show_copies_as_adds;
  eb.pool = scratch_pool;

  if (changelist_filter && changelist_filter->nelts)
    SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter,
                                       scratch_pool));

  if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry)
    get_all = TRUE; /* We need unmodified descendants of copies */
  else
    get_all = FALSE;

  /* Walk status handles files and directories */
  SVN_ERR(svn_wc__internal_walk_status(wc_ctx->db, local_abspath, depth,
                                       get_all,
                                       TRUE /* no_ignore */,
                                       FALSE /* ignore_text_mods */,
                                       NULL /* ignore_patterns */,
                                       diff_status_callback, &eb,
                                       cancel_func, cancel_baton,
                                       scratch_pool));

  /* Close the remaining open directories */
  while (eb.cur)
    {
      struct node_state_t *ns = eb.cur;

      if (!ns->skip)
        {
          if (ns->propchanges)
            SVN_ERR(processor->dir_changed(ns->relpath,
                                           ns->left_src,
                                           ns->right_src,
                                           ns->left_props,
                                           ns->right_props,
                                           ns->propchanges,
                                           ns->baton,
                                           processor,
                                           ns->pool));
          else
            SVN_ERR(processor->dir_closed(ns->relpath,
                                          ns->left_src,
                                          ns->right_src,
                                          ns->baton,
                                          processor,
                                          ns->pool));
        }
      eb.cur = ns->parent;
      svn_pool_clear(ns->pool);
    }

  return SVN_NO_ERROR;
}
Пример #8
0
/* This implements `svn_log_entry_receiver_t'.
   BATON is a `struct log_receiver_baton *'.  */
static svn_error_t *
log_receiver(void *baton,
             svn_log_entry_t *log_entry,
             apr_pool_t *pool)
{
  struct log_receiver_baton *lrb = baton;
  apr_pool_t *iterpool = svn_pool_create(pool);

  SVN_ERR(maybe_send_header(lrb));

  if (log_entry->revision == SVN_INVALID_REVNUM)
    {
      /* If the stack depth is zero, we've seen the last revision, so don't
         send it, just return.  The footer will be sent later. */
      if (lrb->stack_depth == 0)
        return SVN_NO_ERROR;
      else
        lrb->stack_depth--;
    }

  SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output,
                                  "<S:log-item>" DEBUG_CR "<D:version-name>%ld"
                                  "</D:version-name>" DEBUG_CR,
                                  log_entry->revision));

  if (log_entry->revprops)
    {
      apr_hash_index_t *hi;
      for (hi = apr_hash_first(pool, log_entry->revprops);
           hi != NULL;
           hi = apr_hash_next(hi))
        {
          char *name;
          void *val;
          const svn_string_t *value;
          const char *encoding_str = "";

          svn_pool_clear(iterpool);
          apr_hash_this(hi, (void *)&name, NULL, &val);
          value = val;

          /* If the client is okay with us encoding binary (or really,
             any non-XML-safe) property values, do so as necessary. */
          if (lrb->encode_binary_props)
            {
              if (! svn_xml_is_xml_safe(value->data, value->len))
                {
                  value = svn_base64_encode_string2(value, TRUE, iterpool);
                  encoding_str = " encoding=\"base64\"";
                }
            }

          if (strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<D:creator-displayname%s>%s</D:creator-displayname>"
                     DEBUG_CR, encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
          else if (strcmp(name, SVN_PROP_REVISION_DATE) == 0)
            /* ### this should be DAV:creation-date, but we need to format
               ### that date a bit differently */
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<S:date%s>%s</S:date>" DEBUG_CR, encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
          else if (strcmp(name, SVN_PROP_REVISION_LOG) == 0)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<D:comment%s>%s</D:comment>" DEBUG_CR, encoding_str,
                     apr_xml_quote_string(pool,
                                          svn_xml_fuzzy_escape(value->data,
                                                               iterpool), 0)));
          else
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<S:revprop name=\"%s\"%s>%s</S:revprop>" DEBUG_CR,
                     apr_xml_quote_string(iterpool, name, 0), encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
        }
    }

  if (log_entry->has_children)
    {
      SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, "<S:has-children/>"));
      lrb->stack_depth++;
    }

  if (log_entry->subtractive_merge)
    SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                  "<S:subtractive-merge/>"));

  if (log_entry->changed_paths2)
    {
      apr_hash_index_t *hi;
      char *path;

      for (hi = apr_hash_first(pool, log_entry->changed_paths2);
           hi != NULL;
           hi = apr_hash_next(hi))
        {
          void *val;
          svn_log_changed_path2_t *log_item;
          const char *close_element = NULL;

          svn_pool_clear(iterpool);
          apr_hash_this(hi, (void *) &path, NULL, &val);
          log_item = val;

          /* ### todo: is there a D: namespace equivalent for
             `changed-path'?  Should use it if so. */
          switch (log_item->action)
            {
            case 'A':
            case 'R':
              SVN_ERR(start_path_with_copy_from(&close_element, lrb,
                                                log_item, iterpool));
              break;

            case 'D':
              SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                            "<S:deleted-path"));
              close_element = "S:deleted-path";
              break;

            case 'M':
              SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                            "<S:modified-path"));
              close_element = "S:modified-path";
              break;

            default:
              break;
            }

          /* If we need to close the element, then send the attributes
             that apply to all changed items and then close the element. */
          if (close_element)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     " node-kind=\"%s\""
                     " text-mods=\"%s\""
                     " prop-mods=\"%s\">%s</%s>" DEBUG_CR,
                     svn_node_kind_to_word(log_item->node_kind),
                     svn_tristate__to_word(log_item->text_modified),
                     svn_tristate__to_word(log_item->props_modified),
                     apr_xml_quote_string(iterpool, path, 0),
                     close_element));
        }
    }

  svn_pool_destroy(iterpool);

  SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                "</S:log-item>" DEBUG_CR));

  /* In general APR will flush the brigade every 8000 bytes through the filter
     stack, but log items may not be generated that fast, especially in
     combination with authz and busy servers. We now explictly flush after
     log-item 4, 16, 64 and 256 to produce a few results fast.

     This introduces 4 full flushes of our brigade and the installed output
     filters at growing intervals and then falls back to the standard
     buffering of 8000 bytes + whatever buffers are added in output filters. */
  lrb->result_count++;
  if (lrb->result_count == lrb->next_forced_flush)
    {
      apr_status_t apr_err;

      /* This flush is similar to that in dav_svn__final_flush_or_error().

         Compared to using ap_filter_flush(), which we use in other place
         this adds a flush frame before flushing the brigade, to make output
         filters perform a flush as well */

      /* No brigade empty check. We want output filters to flush anyway */
      apr_err = ap_fflush(lrb->output, lrb->bb);
      if (apr_err)
        return svn_error_create(apr_err, NULL, NULL);

      /* Check for an aborted connection, just like our brigade write
         helper functions, since the brigade functions don't appear to
         be return useful errors when the connection is dropped. */
      if (lrb->output->c->aborted)
        return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED,
                                NULL, NULL);

      if (lrb->result_count < 256)
        lrb->next_forced_flush = lrb->next_forced_flush * 4;
    }

  return SVN_NO_ERROR;
}
Пример #9
0
svn_error_t *
svn_fs_bdb__changes_fetch(apr_hash_t **changes_p,
                          svn_fs_t *fs,
                          const char *key,
                          trail_t *trail,
                          apr_pool_t *pool)
{
  base_fs_data_t *bfd = fs->fsap_data;
  DBC *cursor;
  DBT query, result;
  int db_err = 0, db_c_err = 0;
  svn_error_t *err = SVN_NO_ERROR;
  apr_hash_t *changes = apr_hash_make(pool);
  apr_pool_t *subpool = svn_pool_create(pool);

  /* Get a cursor on the first record matching KEY, and then loop over
     the records, adding them to the return array. */
  svn_fs_base__trail_debug(trail, "changes", "cursor");
  SVN_ERR(BDB_WRAP(fs, _("creating cursor for reading changes"),
                   bfd->changes->cursor(bfd->changes, trail->db_txn,
                                        &cursor, 0)));

  /* Advance the cursor to the key that we're looking for. */
  svn_fs_base__str_to_dbt(&query, key);
  svn_fs_base__result_dbt(&result);
  db_err = svn_bdb_dbc_get(cursor, &query, &result, DB_SET);
  if (! db_err)
    svn_fs_base__track_dbt(&result, pool);

  while (! db_err)
    {
      change_t *change;
      skel_t *result_skel;

      /* Clear the per-iteration subpool. */
      svn_pool_clear(subpool);

      /* RESULT now contains a change record associated with KEY.  We
         need to parse that skel into an change_t structure ...  */
      result_skel = svn_fs_base__parse_skel(result.data, result.size,
                                            subpool);
      if (! result_skel)
        {
          err = svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Error reading changes for key '%s'"),
                                  key);
          goto cleanup;
        }
      err = svn_fs_base__parse_change_skel(&change, result_skel, subpool);
      if (err)
        goto cleanup;

      /* ... and merge it with our return hash.  */
      err = fold_change(changes, change);
      if (err)
        goto cleanup;

      /* Now, if our change was a deletion or replacement, we have to
         blow away any changes thus far on paths that are (or, were)
         children of this path.
         ### i won't bother with another iteration pool here -- at
             most we talking about a few extra dups of paths into what
             is already a temporary subpool.
      */
      if ((change->kind == svn_fs_path_change_delete)
          || (change->kind == svn_fs_path_change_replace))
        {
          apr_hash_index_t *hi;

          for (hi = apr_hash_first(subpool, changes);
               hi;
               hi = apr_hash_next(hi))
            {
              /* KEY is the path. */
              const void *hashkey;
              apr_ssize_t klen;
              apr_hash_this(hi, &hashkey, &klen, NULL);

              /* If we come across our own path, ignore it. */
              if (strcmp(change->path, hashkey) == 0)
                continue;

              /* If we come across a child of our path, remove it. */
              if (svn_path_is_child(change->path, hashkey, subpool))
                apr_hash_set(changes, hashkey, klen, NULL);
            }
        }

      /* Advance the cursor to the next record with this same KEY, and
         fetch that record. */
      svn_fs_base__result_dbt(&result);
      db_err = svn_bdb_dbc_get(cursor, &query, &result, DB_NEXT_DUP);
      if (! db_err)
        svn_fs_base__track_dbt(&result, pool);
    }

  /* Destroy the per-iteration subpool. */
  svn_pool_destroy(subpool);

  /* If there are no (more) change records for this KEY, we're
     finished.  Just return the (possibly empty) array.  Any other
     error, however, needs to get handled appropriately.  */
  if (db_err && (db_err != DB_NOTFOUND))
    err = BDB_WRAP(fs, _("fetching changes"), db_err);

 cleanup:
  /* Close the cursor. */
  db_c_err = svn_bdb_dbc_close(cursor);

  /* If we had an error prior to closing the cursor, return the error. */
  if (err)
    return err;

  /* If our only error thus far was when we closed the cursor, return
     that error. */
  if (db_c_err)
    SVN_ERR(BDB_WRAP(fs, _("closing changes cursor"), db_c_err));

  /* Finally, set our return variable and get outta here. */
  *changes_p = changes;
  return SVN_NO_ERROR;
}
Пример #10
0
svn_error_t *
svn_ra__file_revs_from_log(svn_ra_session_t *ra_session,
                           const char *path,
                           svn_revnum_t start,
                           svn_revnum_t end,
                           svn_file_rev_handler_t handler,
                           void *handler_baton,
                           apr_pool_t *pool)
{
  svn_node_kind_t kind;
  const char *repos_url, *session_url, *fs_path;
  apr_array_header_t *condensed_targets;
  struct fr_log_message_baton lmb;
  struct rev *rev;
  apr_hash_t *last_props;
  svn_stream_t *last_stream;
  apr_pool_t *currpool, *lastpool;

  /* Fetch the absolute FS path associated with PATH. */
  SVN_ERR(get_fs_path(&fs_path, ra_session, path, pool));

  /* Check to make sure we're dealing with a file. */
  SVN_ERR(svn_ra_check_path(ra_session, path, end, &kind, pool));
  if (kind == svn_node_dir)
    return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
                             _("'%s' is not a file"), fs_path);

  condensed_targets = apr_array_make(pool, 1, sizeof(const char *));
  APR_ARRAY_PUSH(condensed_targets, const char *) = path;

  lmb.path = fs_path;
  lmb.eldest = NULL;
  lmb.pool = pool;

  /* Accumulate revision metadata by walking the revisions
     backwards; this allows us to follow moves/copies
     correctly. */
  SVN_ERR(svn_ra_get_log2(ra_session,
                          condensed_targets,
                          end, start, 0, /* no limit */
                          TRUE, FALSE, FALSE,
                          NULL, fr_log_message_receiver, &lmb,
                          pool));

  /* Reparent the session while we go back through the history. */
  SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, pool));
  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, pool));
  SVN_ERR(svn_ra_reparent(ra_session, repos_url, pool));

  currpool = svn_pool_create(pool);
  lastpool = svn_pool_create(pool);

  /* We want the first txdelta to be against the empty file. */
  last_props = apr_hash_make(lastpool);
  last_stream = svn_stream_empty(lastpool);

  /* Walk the revision list in chronological order, downloading each fulltext,
     diffing it with its predecessor, and calling the file_revs handler for
     each one.  Use two iteration pools rather than one, because the diff
     routines need to look at a sliding window of revisions.  Two pools gives
     us a ring buffer of sorts. */
  for (rev = lmb.eldest; rev; rev = rev->next)
    {
      const char *temp_path;
      apr_pool_t *tmppool;
      apr_hash_t *props;
      apr_file_t *file;
      svn_stream_t *stream;
      apr_array_header_t *prop_diffs;
      svn_txdelta_stream_t *delta_stream;
      svn_txdelta_window_handler_t delta_handler = NULL;
      void *delta_baton = NULL;

      svn_pool_clear(currpool);

      /* Get the contents of the file from the repository, and put them in
         a temporary local file. */
      SVN_ERR(svn_stream_open_unique(&stream, &temp_path, NULL,
                                     svn_io_file_del_on_pool_cleanup,
                                     currpool, currpool));
      SVN_ERR(svn_ra_get_file(ra_session, rev->path + 1, rev->revision,
                              stream, NULL, &props, currpool));
      SVN_ERR(svn_stream_close(stream));

      /* Open up a stream to the local file. */
      SVN_ERR(svn_io_file_open(&file, temp_path, APR_READ, APR_OS_DEFAULT,
                               currpool));
      stream = svn_stream_from_aprfile2(file, FALSE, currpool);

      /* Calculate the property diff */
      SVN_ERR(svn_prop_diffs(&prop_diffs, props, last_props, lastpool));

      /* Call the file_rev handler */
      SVN_ERR(handler(handler_baton, rev->path, rev->revision, rev->props,
                      FALSE, /* merged revision */
                      &delta_handler, &delta_baton, prop_diffs, lastpool));

      /* Compute and send delta if client asked for it. */
      if (delta_handler)
        {
          /* Get the content delta. Don't calculate checksums as we don't
           * use them. */
          svn_txdelta2(&delta_stream, last_stream, stream, FALSE, lastpool);

          /* And send. */
          SVN_ERR(svn_txdelta_send_txstream(delta_stream, delta_handler,
                                            delta_baton, lastpool));
        }

      /* Switch the pools and data for the next iteration */
      tmppool = currpool;
      currpool = lastpool;
      lastpool = tmppool;

      SVN_ERR(svn_stream_close(last_stream));
      last_stream = stream;
      last_props = props;
    }

  SVN_ERR(svn_stream_close(last_stream));
  svn_pool_destroy(currpool);
  svn_pool_destroy(lastpool);

  /* Reparent the session back to the original URL. */
  return svn_ra_reparent(ra_session, session_url, pool);
}
Пример #11
0
svn_error_t *
svn_ra__get_inherited_props_walk(svn_ra_session_t *session,
                                 const char *path,
                                 svn_revnum_t revision,
                                 apr_array_header_t **inherited_props,
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool)
{
  const char *repos_root_url;
  const char *session_url;
  const char *parent_url;
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);

  *inherited_props =
    apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *));

  /* Walk to the root of the repository getting inherited
     props for PATH. */
  SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, scratch_pool));
  SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool));
  parent_url = session_url;

  while (strcmp(repos_root_url, parent_url))
    {
      apr_hash_index_t *hi;
      apr_hash_t *parent_props;
      apr_hash_t *final_hash = apr_hash_make(result_pool);
      svn_error_t *err;

      svn_pool_clear(iterpool);
      parent_url = svn_uri_dirname(parent_url, scratch_pool);
      SVN_ERR(svn_ra_reparent(session, parent_url, iterpool));
      err = session->vtable->get_dir(session, NULL, NULL,
                                     &parent_props, "",
                                     revision, SVN_DIRENT_ALL,
                                     iterpool);

      /* If the user doesn't have read access to a parent path then
         skip, but allow them to inherit from further up. */
      if (err)
        {
          if ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED)
              || (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN))
            {
              svn_error_clear(err);
              continue;
            }
          else
            {
              return svn_error_trace(err);
            }
        }

      for (hi = apr_hash_first(scratch_pool, parent_props);
           hi;
           hi = apr_hash_next(hi))
        {
          const char *name = apr_hash_this_key(hi);
          apr_ssize_t klen = apr_hash_this_key_len(hi);
          svn_string_t *value = apr_hash_this_val(hi);

          if (svn_property_kind2(name) == svn_prop_regular_kind)
            {
              name = apr_pstrdup(result_pool, name);
              value = svn_string_dup(value, result_pool);
              apr_hash_set(final_hash, name, klen, value);
            }
        }

      if (apr_hash_count(final_hash))
        {
          svn_prop_inherited_item_t *new_iprop =
            apr_palloc(result_pool, sizeof(*new_iprop));
          new_iprop->path_or_url = svn_uri_skip_ancestor(repos_root_url,
                                                         parent_url,
                                                         result_pool);
          new_iprop->prop_hash = final_hash;
          svn_sort__array_insert(*inherited_props, &new_iprop, 0);
        }
    }

  /* Reparent session back to original URL. */
  SVN_ERR(svn_ra_reparent(session, session_url, scratch_pool));

  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
Пример #12
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__null_list(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_pool_create(pool);
  apr_uint32_t dirent_fields;
  struct print_baton pb = { FALSE };
  svn_boolean_t seen_nonexistent_target = FALSE;
  svn_error_t *err;

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

  /* Add "." if user passed 0 arguments */
  svn_opt_push_implicit_dot_target(targets, pool);

  if (opt_state->verbose)
    dirent_fields = SVN_DIRENT_ALL;
  else
    dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */

  pb.ctx = ctx;
  pb.verbose = opt_state->verbose;

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

  /* For each target, try to list it. */
  for (i = 0; i < targets->nelts; i++)
    {
      const char *target = APR_ARRAY_IDX(targets, i, const char *);
      const char *truepath;
      svn_opt_revision_t peg_revision;

      svn_pool_clear(subpool);

      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

      /* Get peg revisions. */
      SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
                                 subpool));

      err = svn_client_list3(truepath, &peg_revision,
                             &(opt_state->start_revision),
                             opt_state->depth,
                             dirent_fields,
                             opt_state->verbose,
                             FALSE, /* include externals */
                             print_dirent,
                             &pb, ctx, subpool);

      if (err)
        {
          /* If one of the targets is a non-existent URL or wc-entry,
             don't bail out.  Just warn and move on to the next target. */
          if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
              err->apr_err == SVN_ERR_FS_NOT_FOUND)
              svn_handle_warning2(stderr, err, "svnbench: ");
          else
              return svn_error_trace(err);

          svn_error_clear(err);
          err = NULL;
          seen_nonexistent_target = TRUE;
        }
      else if (!opt_state->quiet)
        SVN_ERR(svn_cmdline_printf(pool,
                                   _("%15s directories\n"
                                     "%15s files\n"
                                     "%15s locks\n"),
                                   svn__ui64toa_sep(pb.directories, ',', pool),
                                   svn__ui64toa_sep(pb.files, ',', pool),
                                   svn__ui64toa_sep(pb.locks, ',', pool)));
    }

  svn_pool_destroy(subpool);

  if (seen_nonexistent_target)
    return svn_error_create(
      SVN_ERR_ILLEGAL_TARGET, NULL,
      _("Could not list all targets because some targets don't exist"));
  else
    return SVN_NO_ERROR;
}
Пример #13
0
/* The real implementation of svn_client__get_inheritable_props */
static svn_error_t *
get_inheritable_props(apr_hash_t **wcroot_iprops,
                      const char *local_abspath,
                      svn_revnum_t revision,
                      svn_depth_t depth,
                      svn_ra_session_t *ra_session,
                      svn_client_ctx_t *ctx,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
{
  apr_hash_t *iprop_paths;
  apr_hash_index_t *hi;
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
  apr_pool_t *session_pool = NULL;
  *wcroot_iprops = apr_hash_make(result_pool);

  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));

  /* If we don't have a base revision for LOCAL_ABSPATH then it can't
     possibly be a working copy root, nor can it contain any WC roots
     in the form of switched subtrees.  So there is nothing to cache. */

  SVN_ERR(svn_wc__get_cached_iprop_children(&iprop_paths, depth,
                                            ctx->wc_ctx, local_abspath,
                                            scratch_pool, iterpool));

  /* If we are in the midst of a checkout or an update that is bringing in
     an external, then svn_wc__get_cached_iprop_children won't return
     LOCAL_ABSPATH in IPROPS_PATHS because the former has no cached iprops
     yet.  So make sure LOCAL_ABSPATH is present if it's a WC root. */
  if (!svn_hash_gets(iprop_paths, local_abspath))
    {
      svn_boolean_t needs_cached_iprops;

      SVN_ERR(need_to_cache_iprops(&needs_cached_iprops, local_abspath,
                                   ra_session, ctx, iterpool));
      if (needs_cached_iprops)
        {
          const char *target_abspath = apr_pstrdup(scratch_pool,
                                                   local_abspath);

          /* As value we set TARGET_ABSPATH, but any string besides ""
             would do */
          svn_hash_sets(iprop_paths, target_abspath, target_abspath);
        }
    }

      for (hi = apr_hash_first(scratch_pool, iprop_paths);
           hi;
           hi = apr_hash_next(hi))
        {
          const char *child_abspath = svn__apr_hash_index_key(hi);
          const char *child_repos_relpath = svn__apr_hash_index_val(hi);
          const char *url;
          apr_array_header_t *inherited_props;
          svn_error_t *err;

          svn_pool_clear(iterpool);

          if (*child_repos_relpath == '\0')
            {
              /* A repository root doesn't have inherited properties */
              continue;
            }

          SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child_abspath,
                                       iterpool, iterpool));
          if (ra_session)
            SVN_ERR(svn_ra_reparent(ra_session, url, scratch_pool));
          else
            {
              if (! session_pool)
                session_pool = svn_pool_create(scratch_pool);

              SVN_ERR(svn_client_open_ra_session2(&ra_session, url, NULL,
                                                  ctx,
                                                  session_pool, iterpool));
            }

          err = svn_ra_get_inherited_props(ra_session, &inherited_props,
                                           "", revision,
                                           result_pool, iterpool);

          if (err)
            {
              if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
                return svn_error_trace(err);

              svn_error_clear(err);
              continue;
            }

          svn_hash_sets(*wcroot_iprops,
                        apr_pstrdup(result_pool, child_abspath),
                        inherited_props);
        }


  svn_pool_destroy(iterpool);
  if (session_pool)
    svn_pool_destroy(session_pool);

  return SVN_NO_ERROR;

}
Пример #14
0
svn_error_t *
svn_ra_neon__search_for_starting_props(svn_ra_neon__resource_t **rsrc,
                                       const char **missing_path,
                                       svn_ra_neon__session_t *sess,
                                       const char *url,
                                       apr_pool_t *pool)
{
  svn_error_t *err = SVN_NO_ERROR;
  apr_size_t len;
  svn_stringbuf_t *path_s;
  ne_uri parsed_url;
  svn_stringbuf_t *lopped_path =
    svn_stringbuf_create(url, pool); /* initialize to make sure it'll fit
                                        without reallocating */
  apr_pool_t *iterpool = svn_pool_create(pool);

  /* Split the url into its component pieces (scheme, host, path,
     etc).  We want the path part. */
  ne_uri_parse(url, &parsed_url);
  if (parsed_url.path == NULL)
    {
      ne_uri_free(&parsed_url);
      return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                               _("Neon was unable to parse URL '%s'"), url);
    }

  svn_stringbuf_setempty(lopped_path);
  path_s = svn_stringbuf_create(parsed_url.path, pool);
  ne_uri_free(&parsed_url);

  /* Try to get the starting_props from the public url.  If the
     resource no longer exists in HEAD, we'll get a failure.  That's
     fine: just keep removing components and trying to get the
     starting_props from parent directories. */
  while (! svn_path_is_empty(path_s->data))
    {
      svn_pool_clear(iterpool);
      err = svn_ra_neon__get_starting_props(rsrc, sess, path_s->data,
                                            NULL, iterpool);
      if (! err)
        break;   /* found an existing parent! */

      if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
        return err;  /* found a _real_ error */

      /* else... lop off the basename and try again. */
      svn_stringbuf_set(lopped_path,
                        svn_path_join(svn_path_basename(path_s->data, iterpool),
                                      lopped_path->data, iterpool));

      len = path_s->len;
      svn_path_remove_component(path_s);

      /* if we detect an infinite loop, get out. */
      if (path_s->len == len)
        return svn_error_quick_wrap
          (err, _("The path was not part of a repository"));

      svn_error_clear(err);
    }

  /* error out if entire URL was bogus (not a single part of it exists
     in the repository!)  */
  if (svn_path_is_empty(path_s->data))
    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                             _("No part of path '%s' was found in "
                               "repository HEAD"), parsed_url.path);

  /* Duplicate rsrc out of iterpool into pool */
  {
    apr_hash_index_t *hi;
    svn_ra_neon__resource_t *tmp = apr_pcalloc(pool, sizeof(*tmp));
    tmp->url = apr_pstrdup(pool, (*rsrc)->url);
    tmp->is_collection = (*rsrc)->is_collection;
    tmp->pool = pool;
    tmp->propset = apr_hash_make(pool);

    for (hi = apr_hash_first(iterpool, (*rsrc)->propset);
         hi; hi = apr_hash_next(hi))
      {
        const void *key;
        void *val;

        apr_hash_this(hi, &key, NULL, &val);
        apr_hash_set(tmp->propset, apr_pstrdup(pool, key), APR_HASH_KEY_STRING,
                     svn_string_dup(val, pool));
      }

    *rsrc = tmp;
  }
  *missing_path = lopped_path->data;
  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
Пример #15
0
svn_error_t *
svn_repos_parse_dumpstream3(svn_stream_t *stream,
                            const svn_repos_parse_fns3_t *parse_fns,
                            void *parse_baton,
                            svn_boolean_t deltas_are_text,
                            svn_cancel_func_t cancel_func,
                            void *cancel_baton,
                            apr_pool_t *pool)
{
  svn_boolean_t eof;
  svn_stringbuf_t *linebuf;
  void *rev_baton = NULL;
  char *buffer = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
  apr_size_t buflen = SVN__STREAM_CHUNK_SIZE;
  apr_pool_t *linepool = svn_pool_create(pool);
  apr_pool_t *revpool = svn_pool_create(pool);
  apr_pool_t *nodepool = svn_pool_create(pool);
  int version;

  SVN_ERR(svn_stream_readline(stream, &linebuf, "\n", &eof, linepool));
  if (eof)
    return stream_ran_dry();

  /* The first two lines of the stream are the dumpfile-format version
     number, and a blank line.  To preserve backward compatibility,
     don't assume the existence of newer parser-vtable functions. */
  SVN_ERR(parse_format_version(&version, linebuf->data));
  if (parse_fns->magic_header_record != NULL)
    SVN_ERR(parse_fns->magic_header_record(version, parse_baton, pool));

  /* A dumpfile "record" is defined to be a header-block of
     rfc822-style headers, possibly followed by a content-block.

       - A header-block is always terminated by a single blank line (\n\n)

       - We know whether the record has a content-block by looking for
         a 'Content-length:' header.  The content-block will always be
         of a specific length, plus an extra newline.

     Once a record is fully sucked from the stream, an indeterminate
     number of blank lines (or lines that begin with whitespace) may
     follow before the next record (or the end of the stream.)
  */

  while (1)
    {
      apr_hash_t *headers;
      void *node_baton;
      svn_boolean_t found_node = FALSE;
      svn_boolean_t old_v1_with_cl = FALSE;
      const char *content_length;
      const char *prop_cl;
      const char *text_cl;
      const char *value;
      svn_filesize_t actual_prop_length;

      /* Clear our per-line pool. */
      svn_pool_clear(linepool);

      /* Check for cancellation. */
      if (cancel_func)
        SVN_ERR(cancel_func(cancel_baton));

      /* Keep reading blank lines until we discover a new record, or until
         the stream runs out. */
      SVN_ERR(svn_stream_readline(stream, &linebuf, "\n", &eof, linepool));

      if (eof)
        {
          if (svn_stringbuf_isempty(linebuf))
            break;   /* end of stream, go home. */
          else
            return stream_ran_dry();
        }

      if ((linebuf->len == 0) || (svn_ctype_isspace(linebuf->data[0])))
        continue; /* empty line ... loop */

      /*** Found the beginning of a new record. ***/

      /* The last line we read better be a header of some sort.
         Read the whole header-block into a hash. */
      SVN_ERR(read_header_block(stream, linebuf, &headers, linepool));

      /*** Handle the various header blocks. ***/

      /* Is this a revision record? */
      if (svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER))
        {
          /* If we already have a rev_baton open, we need to close it
             and clear the per-revision subpool. */
          if (rev_baton != NULL)
            {
              SVN_ERR(parse_fns->close_revision(rev_baton));
              svn_pool_clear(revpool);
            }

          SVN_ERR(parse_fns->new_revision_record(&rev_baton,
                                                 headers, parse_baton,
                                                 revpool));
        }
      /* Or is this, perhaps, a node record? */
      else if (svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH))
        {
          SVN_ERR(parse_fns->new_node_record(&node_baton,
                                             headers,
                                             rev_baton,
                                             nodepool));
          found_node = TRUE;
        }
      /* Or is this the repos UUID? */
      else if ((value = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_UUID)))
        {
          SVN_ERR(parse_fns->uuid_record(value, parse_baton, pool));
        }
      /* Or perhaps a dumpfile format? */
      /* ### TODO: use parse_format_version */
      else if ((value = svn_hash_gets(headers,
                                      SVN_REPOS_DUMPFILE_MAGIC_HEADER)))
        {
          /* ### someday, switch modes of operation here. */
          SVN_ERR(svn_cstring_atoi(&version, value));
        }
      /* Or is this bogosity?! */
      else
        {
          /* What the heck is this record?!? */
          return svn_error_create(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
                                  _("Unrecognized record type in stream"));
        }

      /* Need 3 values below to determine v1 dump type

         Old (pre 0.14?) v1 dumps don't have Prop-content-length
         and Text-content-length fields, but always have a properties
         block in a block with Content-Length > 0 */

      content_length = svn_hash_gets(headers,
                                     SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
      prop_cl = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
      text_cl = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH);
      old_v1_with_cl =
        version == 1 && content_length && ! prop_cl && ! text_cl;

      /* Is there a props content-block to parse? */
      if (prop_cl || old_v1_with_cl)
        {
          const char *delta = svn_hash_gets(headers,
                                            SVN_REPOS_DUMPFILE_PROP_DELTA);
          svn_boolean_t is_delta = (delta && strcmp(delta, "true") == 0);

          /* First, remove all node properties, unless this is a delta
             property block. */
          if (found_node && !is_delta)
            SVN_ERR(parse_fns->remove_node_props(node_baton));

          SVN_ERR(parse_property_block
                  (stream,
                   svn__atoui64(prop_cl ? prop_cl : content_length),
                   parse_fns,
                   found_node ? node_baton : rev_baton,
                   parse_baton,
                   found_node,
                   &actual_prop_length,
                   found_node ? nodepool : revpool));
        }

      /* Is there a text content-block to parse? */
      if (text_cl)
        {
          const char *delta = svn_hash_gets(headers,
                                            SVN_REPOS_DUMPFILE_TEXT_DELTA);
          svn_boolean_t is_delta = FALSE;
          if (! deltas_are_text)
            is_delta = (delta && strcmp(delta, "true") == 0);

          SVN_ERR(parse_text_block(stream,
                                   svn__atoui64(text_cl),
                                   is_delta,
                                   parse_fns,
                                   found_node ? node_baton : rev_baton,
                                   buffer,
                                   buflen,
                                   found_node ? nodepool : revpool));
        }
      else if (old_v1_with_cl)
        {
          /* An old-v1 block with a Content-length might have a text block.
             If the property block did not consume all the bytes of the
             Content-length, then it clearly does have a text block.
             If not, then we must deduce whether we have an *empty* text
             block or an *absent* text block.  The rules are:
             - "Node-kind: file" blocks have an empty (i.e. present, but
               zero-length) text block, since they represent a file
               modification.  Note that file-copied-text-unmodified blocks
               have no Content-length - even if they should have contained
               a modified property block, the pre-0.14 dumper forgets to
               dump the modified properties.
             - If it is not a file node, then it is a revision or directory,
               and so has an absent text block.
          */
          const char *node_kind;
          svn_filesize_t cl_value = svn__atoui64(content_length)
                                    - actual_prop_length;

          if (cl_value ||
              ((node_kind = svn_hash_gets(headers,
                                          SVN_REPOS_DUMPFILE_NODE_KIND))
               && strcmp(node_kind, "file") == 0)
             )
            SVN_ERR(parse_text_block(stream,
                                     cl_value,
                                     FALSE,
                                     parse_fns,
                                     found_node ? node_baton : rev_baton,
                                     buffer,
                                     buflen,
                                     found_node ? nodepool : revpool));
        }

      /* if we have a content-length header, did we read all of it?
         in case of an old v1, we *always* read all of it, because
         text-content-length == content-length - prop-content-length
      */
      if (content_length && ! old_v1_with_cl)
        {
          apr_size_t rlen, num_to_read;
          svn_filesize_t remaining =
            svn__atoui64(content_length) -
            (prop_cl ? svn__atoui64(prop_cl) : 0) -
            (text_cl ? svn__atoui64(text_cl) : 0);


          if (remaining < 0)
            return svn_error_create(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
                                    _("Sum of subblock sizes larger than "
                                      "total block content length"));

          /* Consume remaining bytes in this content block */
          while (remaining > 0)
            {
              if (remaining >= (svn_filesize_t)buflen)
                rlen = buflen;
              else
                rlen = (apr_size_t) remaining;

              num_to_read = rlen;
              SVN_ERR(svn_stream_read_full(stream, buffer, &rlen));
              remaining -= rlen;
              if (rlen != num_to_read)
                return stream_ran_dry();
            }
        }

      /* If we just finished processing a node record, we need to
         close the node record and clear the per-node subpool. */
      if (found_node)
        {
          SVN_ERR(parse_fns->close_node(node_baton));
          svn_pool_clear(nodepool);
        }

      /*** End of processing for one record. ***/

    } /* end of stream */

  /* Close out whatever revision we're in. */
  if (rev_baton != NULL)
    SVN_ERR(parse_fns->close_revision(rev_baton));

  svn_pool_destroy(linepool);
  svn_pool_destroy(revpool);
  svn_pool_destroy(nodepool);
  return SVN_NO_ERROR;
}
Пример #16
0
void
logger__log_error(logger_t *logger,
                  svn_error_t *err,
                  repository_t *repository,
                  client_info_t *client_info)
{
  if (logger && err)
    {
      const char *timestr, *continuation;
      const char *user, *repos, *remote_host;
      char errbuf[256];
      /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */
      char errstr[8192];

      svn_error_clear(svn_mutex__lock(logger->mutex));

      timestr = svn_time_to_cstring(apr_time_now(), logger->pool);
      remote_host = client_info && client_info->remote_host
                  ? client_info->remote_host
                  : "-";
      user = client_info && client_info->user
           ? client_info->user
           : "******";
      repos = repository && repository->repos_name
            ? repository->repos_name
             : "-";

      continuation = "";
      while (err)
        {
          const char *message = svn_err_best_message(err, errbuf, sizeof(errbuf));
          /* based on httpd-2.2.4/server/log.c:log_error_core */
          apr_size_t len = apr_snprintf(errstr, sizeof(errstr),
                                        "%" APR_PID_T_FMT
                                        " %s %s %s %s ERR%s %s %ld %d ",
                                        getpid(), timestr, remote_host, user,
                                        repos, continuation,
                                        err->file ? err->file : "-", err->line,
                                        err->apr_err);

          len += escape_errorlog_item(errstr + len, message,
                                      sizeof(errstr) - len);
          /* Truncate for the terminator (as apr_snprintf does) */
          if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) {
            len = sizeof(errstr) - sizeof(APR_EOL_STR);
          }

          memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR));
          len += sizeof(APR_EOL_STR) -1;  /* add NL, ex terminating NUL */

          svn_error_clear(svn_stream_write(logger->stream, errstr, &len));

          continuation = "-";
          err = err->child;
        }

      svn_pool_clear(logger->pool);

      svn_error_clear(svn_mutex__unlock(logger->mutex, SVN_NO_ERROR));
    }
}
Пример #17
0
static svn_error_t *
base_hotcopy(const char *src_path,
             const char *dest_path,
             svn_boolean_t clean_logs,
             apr_pool_t *pool)
{
  svn_error_t *err;
  u_int32_t pagesize;
  svn_boolean_t log_autoremove = FALSE;
  int format;

  /* Check the FS format number to be certain that we know how to
     hotcopy this FS.  Pre-1.2 filesystems did not have a format file (you
     could say they were format "0"), so we will error here.  This is not
     optimal, but since this has been the case since 1.2.0, and no one has
     complained, it apparently isn't much of a concern.  (We did not check
     the 'format' file in 1.2.x, but we did blindly try to copy 'locks',
     which would have errored just the same.)  */
  SVN_ERR(svn_io_read_version_file(
          &format, svn_dirent_join(src_path, FORMAT_FILE, pool), pool));
  SVN_ERR(check_format(format));

  /* If using Berkeley DB 4.2 or later, note whether the DB_LOG_AUTO_REMOVE
     feature is on.  If it is, we have a potential race condition:
     another process might delete a logfile while we're in the middle
     of copying all the logfiles.  (This is not a huge deal; at worst,
     the hotcopy fails with a file-not-found error.) */
#if SVN_BDB_VERSION_AT_LEAST(4, 2)
  err = check_env_flags(&log_autoremove,
#if SVN_BDB_VERSION_AT_LEAST(4, 7)
                          DB_LOG_AUTO_REMOVE,
 /* DB_LOG_AUTO_REMOVE was named DB_LOG_AUTOREMOVE before Berkeley DB 4.7. */
#else
                          DB_LOG_AUTOREMOVE,
#endif
                          src_path, pool);
#endif
  SVN_ERR(err);

  /* Copy the DB_CONFIG file. */
  SVN_ERR(svn_io_dir_file_copy(src_path, dest_path, "DB_CONFIG", pool));

  /* In order to copy the database files safely and atomically, we
     must copy them in chunks which are multiples of the page-size
     used by BDB.  See sleepycat docs for details, or svn issue #1818. */
#if SVN_BDB_VERSION_AT_LEAST(4, 2)
  SVN_ERR(get_db_pagesize(&pagesize, src_path, pool));
  if (pagesize < SVN__STREAM_CHUNK_SIZE)
    {
      /* use the largest multiple of BDB pagesize we can. */
      int multiple = SVN__STREAM_CHUNK_SIZE / pagesize;
      pagesize *= multiple;
    }
#else
  /* default to 128K chunks, which should be safe.
     BDB almost certainly uses a power-of-2 pagesize. */
  pagesize = (4096 * 32);
#endif

  /* Copy the databases.  */
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "nodes", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "transactions", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "revisions", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "copies", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "changes", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "representations", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "strings", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "uuids", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "locks", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "lock-tokens", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "node-origins", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "checksum-reps", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "miscellaneous", pagesize, TRUE, pool));

  {
    apr_array_header_t *logfiles;
    int idx;
    apr_pool_t *subpool;

    SVN_ERR(base_bdb_logfiles(&logfiles,
                              src_path,
                              FALSE,   /* All logs */
                              pool));

    /* Process log files. */
    subpool = svn_pool_create(pool);
    for (idx = 0; idx < logfiles->nelts; idx++)
      {
        svn_pool_clear(subpool);
        err = svn_io_dir_file_copy(src_path, dest_path,
                                   APR_ARRAY_IDX(logfiles, idx,
                                                 const char *),
                                   subpool);
        if (err)
          {
            if (log_autoremove)
              return
                svn_error_quick_wrap
                (err,
                 _("Error copying logfile;  the DB_LOG_AUTOREMOVE feature\n"
                   "may be interfering with the hotcopy algorithm.  If\n"
                   "the problem persists, try deactivating this feature\n"
                   "in DB_CONFIG"));
            else
              return svn_error_trace(err);
          }
      }
    svn_pool_destroy(subpool);
  }

  /* Since this is a copy we will have exclusive access to the repository. */
  err = bdb_recover(dest_path, TRUE, pool);
  if (err)
    {
      if (log_autoremove)
        return
          svn_error_quick_wrap
          (err,
           _("Error running catastrophic recovery on hotcopy;  the\n"
             "DB_LOG_AUTOREMOVE feature may be interfering with the\n"
             "hotcopy algorithm.  If the problem persists, try deactivating\n"
             "this feature in DB_CONFIG"));
      else
        return svn_error_trace(err);
    }

  /* Only now that the hotcopied filesystem is complete,
     stamp it with a format file. */
  SVN_ERR(svn_io_write_version_file(
             svn_dirent_join(dest_path, FORMAT_FILE, pool), format, pool));

  if (clean_logs)
    SVN_ERR(svn_fs_base__clean_logs(src_path, dest_path, pool));

  return SVN_NO_ERROR;
}
Пример #18
0
static svn_error_t *
changes_fetch_ordering(const char **msg,
                       svn_boolean_t msg_only,
                       svn_test_opts_t *opts,
                       apr_pool_t *pool)
{
  svn_fs_t *fs;
  svn_revnum_t youngest_rev = 0;
  const char *txn_name;
  svn_fs_txn_t *txn;
  svn_fs_root_t *txn_root, *rev_root;
  struct changes_args args;
  apr_pool_t *subpool = svn_pool_create(pool);
  apr_hash_index_t *hi;

  *msg = "verify ordered-ness of fetched compressed changes";

  if (msg_only)
    return SVN_NO_ERROR;

  /* Create a new fs and repos */
  SVN_ERR(svn_test__create_fs
          (&fs, "test-repo-changes-fetch-ordering",
           "bdb", pool));

  /*** REVISION 1: Make some files and dirs. ***/
  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
  {
    static svn_test__txn_script_command_t script_entries[] = {
      { 'a', "dir1",        0 },
      { 'a', "file1",       "This is the file 'file1'.\n" },
      { 'a', "dir1/file2",  "This is the file 'file2'.\n" },
      { 'a', "dir1/file3",  "This is the file 'file3'.\n" },
      { 'a', "dir1/file4",  "This is the file 'file4'.\n" },
    };
    SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 5, subpool));
  }
  SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
  svn_pool_clear(subpool);

  /*** REVISION 2: Delete and add some stuff, non-depth-first. ***/
  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
  /* Don't use subpool, txn_name is used after subpool is cleared */
  SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
  {
    static svn_test__txn_script_command_t script_entries[] = {
      { 'd', "file1",       "This is the file 'file1'.\n" },
      { 'd', "dir1/file2",  "This is the file 'file2'.\n" },
      { 'd', "dir1/file3",  "This is the file 'file3'.\n" },
      { 'a', "dir1/file5",  "This is the file 'file4'.\n" },
      { 'a', "dir1/dir2",   0 },
      { 'd', "dir1",        0 },
      { 'a', "dir3",        0 },
    };
    SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 7, subpool));
  }
  SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
  svn_pool_clear(subpool);

  /*** TEST:  We should have only three changes, the deletion of 'file1'
       the deletion of 'dir1', and the addition of 'dir3'. ***/
  args.fs = fs;
  args.key = txn_name;
  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_fetch, &args,
                                 subpool));
  if ((! args.changes) || (apr_hash_count(args.changes) != 3))
    return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
                            "expected changes");
  for (hi = apr_hash_first(subpool, args.changes);
       hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      svn_fs_path_change_t *change;

      /* KEY will be the path, VAL the change. */
      apr_hash_this(hi, &key, NULL, &val);
      change = val;

      if ((change->change_kind == svn_fs_path_change_add)
          && (strcmp(key, "/dir3") == 0))
        ;
      else if ((change->change_kind == svn_fs_path_change_delete)
               && ((strcmp(key, "/dir1") == 0)
                   || (strcmp(key, "/file1") == 0)))
        ;
      else
        return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
                                "got wrong changes");
    }

  /*** REVISION 3: Do the same stuff as in revision 1. ***/
  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
  {
    static svn_test__txn_script_command_t script_entries[] = {
      { 'a', "dir1",        0 },
      { 'a', "file1",       "This is the file 'file1'.\n" },
      { 'a', "dir1/file2",  "This is the file 'file2'.\n" },
      { 'a', "dir1/file3",  "This is the file 'file3'.\n" },
      { 'a', "dir1/file4",  "This is the file 'file4'.\n" },
    };
    SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 5, subpool));
  }
  SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
  svn_pool_clear(subpool);

  /*** REVISION 4: Do the same stuff as in revision 2, but use a copy
       overwrite of the top directory (instead of a delete) to test
       that the 'replace' change type works, too.  (And add 'dir4'
       instead of 'dir3', since 'dir3' still exists).  ***/
  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
  /* Don't use subpool, txn_name is used after subpool is cleared */
  SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
  SVN_ERR(svn_fs_revision_root(&rev_root, fs, 1, subpool));
  {
    static svn_test__txn_script_command_t script_entries[] = {
      { 'd', "file1",       "This is the file 'file1'.\n" },
      { 'd', "dir1/file2",  "This is the file 'file2'.\n" },
      { 'd', "dir1/file3",  "This is the file 'file3'.\n" },
      { 'a', "dir1/file5",  "This is the file 'file4'.\n" },
      { 'a', "dir1/dir2",   0 },
    };
    SVN_ERR(svn_test__txn_script_exec(txn_root, script_entries, 5, subpool));
    SVN_ERR(svn_fs_copy(rev_root, "dir1", txn_root, "dir1", subpool));
    SVN_ERR(svn_fs_make_dir(txn_root, "dir4", subpool));
  }
  SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn, subpool));
  svn_pool_clear(subpool);

  /*** TEST:  We should have only three changes, the deletion of 'file1'
       the replacement of 'dir1', and the addition of 'dir4'. ***/
  args.fs = fs;
  args.key = txn_name;
  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_changes_fetch, &args,
                                 subpool));
  if ((! args.changes) || (apr_hash_count(args.changes) != 3))
    return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
                            "expected changes");
  for (hi = apr_hash_first(subpool, args.changes);
       hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      svn_fs_path_change_t *change;

      /* KEY will be the path, VAL the change. */
      apr_hash_this(hi, &key, NULL, &val);
      change = val;

      if ((change->change_kind == svn_fs_path_change_add)
          && (strcmp(key, "/dir4") == 0))
        ;
      else if ((change->change_kind == svn_fs_path_change_replace)
               && (strcmp(key, "/dir1") == 0))
        ;
      else if ((change->change_kind == svn_fs_path_change_delete)
               && (strcmp(key, "/file1") == 0))
        ;
      else
        return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
                                "got wrong changes");
    }

  return SVN_NO_ERROR;
}
Пример #19
0
/* Implements svn_wc_status_func3_t */
static svn_error_t *
diff_status_callback(void *baton,
                     const char *local_abspath,
                     const svn_wc_status3_t *status,
                     apr_pool_t *scratch_pool)
{
  struct diff_baton *eb = baton;
  svn_wc__db_t *db = eb->db;

  switch (status->node_status)
    {
      case svn_wc_status_unversioned:
      case svn_wc_status_ignored:
        return SVN_NO_ERROR; /* No diff */

      case svn_wc_status_conflicted:
        if (status->text_status == svn_wc_status_none
            && status->prop_status == svn_wc_status_none)
          {
            /* Node is an actual only node describing a tree conflict */
            return SVN_NO_ERROR;
          }
        break;

      default:
        break; /* Go check other conditions */
    }

  /* Not text/prop modified, not copied. Easy out */
  if (status->node_status == svn_wc_status_normal && !status->copied)
    return SVN_NO_ERROR;

  /* Mark all directories where we are no longer inside as closed */
  while (eb->cur
         && !svn_dirent_is_ancestor(eb->cur->local_abspath, local_abspath))
    {
      struct node_state_t *ns = eb->cur;

      if (!ns->skip)
        {
          if (ns->propchanges)
            SVN_ERR(eb->processor->dir_changed(ns->relpath,
                                               ns->left_src,
                                               ns->right_src,
                                               ns->left_props,
                                               ns->right_props,
                                               ns->propchanges,
                                               ns->baton,
                                               eb->processor,
                                               ns->pool));
          else
            SVN_ERR(eb->processor->dir_closed(ns->relpath,
                                              ns->left_src,
                                              ns->right_src,
                                              ns->baton,
                                              eb->processor,
                                              ns->pool));
        }
      eb->cur = ns->parent;
      svn_pool_clear(ns->pool);
    }
  SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
                       FALSE, scratch_pool));

  if (eb->cur && eb->cur->skip_children)
    return SVN_NO_ERROR;

  if (eb->changelist_hash != NULL
      && (!status->changelist
          || ! svn_hash_gets(eb->changelist_hash, status->changelist)))
    return SVN_NO_ERROR; /* Filtered via changelist */

  /* This code does about the same thing as the inner body of
     walk_local_nodes_diff() in diff_editor.c, except that
     it is already filtered by the status walker, doesn't have to
     account for remote changes (and many tiny other details) */

  {
    svn_boolean_t repos_only;
    svn_boolean_t local_only;
    svn_wc__db_status_t db_status;
    svn_boolean_t have_base;
    svn_node_kind_t base_kind;
    svn_node_kind_t db_kind = status->kind;
    svn_depth_t depth_below_here = svn_depth_unknown;

    const char *child_abspath = local_abspath;
    const char *child_relpath = svn_dirent_skip_ancestor(eb->anchor_abspath,
                                                         local_abspath);


    repos_only = FALSE;
    local_only = FALSE;

    /* ### optimize away this call using status info. Should
           be possible in almost every case (except conflict, missing, obst.)*/
    SVN_ERR(svn_wc__db_read_info(&db_status, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL,
                                 &have_base, NULL, NULL,
                                 eb->db, local_abspath,
                                 scratch_pool, scratch_pool));
    if (!have_base)
      {
        local_only = TRUE; /* Only report additions */
      }
    else if (db_status == svn_wc__db_status_normal)
      {
        /* Simple diff */
        base_kind = db_kind;
      }
    else if (db_status == svn_wc__db_status_deleted)
      {
        svn_wc__db_status_t base_status;
        repos_only = TRUE;
        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL,
                                         eb->db, local_abspath,
                                         scratch_pool, scratch_pool));

        if (base_status != svn_wc__db_status_normal)
          return SVN_NO_ERROR;
      }
    else
      {
        /* working status is either added or deleted */
        svn_wc__db_status_t base_status;

        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL,
                                         eb->db, local_abspath,
                                         scratch_pool, scratch_pool));

        if (base_status != svn_wc__db_status_normal)
          local_only = TRUE;
        else if (base_kind != db_kind || !eb->ignore_ancestry)
          {
            repos_only = TRUE;
            local_only = TRUE;
          }
      }

    if (repos_only)
      {
        /* Report repository form deleted */
        if (base_kind == svn_node_file)
          SVN_ERR(svn_wc__diff_base_only_file(db, child_abspath,
                                              child_relpath,
                                              SVN_INVALID_REVNUM,
                                              eb->processor,
                                              eb->cur ? eb->cur->baton : NULL,
                                              scratch_pool));
        else if (base_kind == svn_node_dir)
          SVN_ERR(svn_wc__diff_base_only_dir(db, child_abspath,
                                             child_relpath,
                                             SVN_INVALID_REVNUM,
                                             depth_below_here,
                                             eb->processor,
                                             eb->cur ? eb->cur->baton : NULL,
                                             eb->cancel_func,
                                             eb->cancel_baton,
                                             scratch_pool));
      }
    else if (!local_only)
      {
        /* Diff base against actual */
        if (db_kind == svn_node_file)
          {
            SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
                                                   child_relpath,
                                                   SVN_INVALID_REVNUM,
                                                   eb->changelist_hash,
                                                   eb->processor,
                                                   eb->cur
                                                        ? eb->cur->baton
                                                        : NULL,
                                                   FALSE,
                                                   eb->cancel_func,
                                                   eb->cancel_baton,
                                                   scratch_pool));
          }
        else if (db_kind == svn_node_dir)
          {
            SVN_ERR(ensure_state(eb, local_abspath, FALSE, scratch_pool));

            if (status->prop_status != svn_wc_status_none
                && status->prop_status != svn_wc_status_normal)
              {
                apr_array_header_t *propchanges;
                SVN_ERR(svn_wc__db_base_get_props(&eb->cur->left_props,
                                                  eb->db, local_abspath,
                                                  eb->cur->pool,
                                                  scratch_pool));
                SVN_ERR(svn_wc__db_read_props(&eb->cur->right_props,
                                              eb->db, local_abspath,
                                              eb->cur->pool,
                                              scratch_pool));

                SVN_ERR(svn_prop_diffs(&propchanges,
                                       eb->cur->right_props,
                                       eb->cur->left_props,
                                       eb->cur->pool));

                eb->cur->propchanges = propchanges;
              }
          }
      }

    if (local_only)
      {
        if (db_kind == svn_node_file)
          SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
                                               child_relpath,
                                               eb->processor,
                                               eb->cur ? eb->cur->baton : NULL,
                                               eb->changelist_hash,
                                               FALSE,
                                               eb->cancel_func,
                                               eb->cancel_baton,
                                               scratch_pool));
        else if (db_kind == svn_node_dir)
          SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
                                              child_relpath, depth_below_here,
                                              eb->processor,
                                              eb->cur ? eb->cur->baton : NULL,
                                              eb->changelist_hash,
                                              FALSE,
                                              eb->cancel_func,
                                              eb->cancel_baton,
                                              scratch_pool));
      }

    if (db_kind == svn_node_dir && (local_only || repos_only))
      SVN_ERR(ensure_state(eb, local_abspath, TRUE /* skip */, scratch_pool));
  }

  return SVN_NO_ERROR;
}
Пример #20
0
/* This implements the `svn_opt_subcommand_t' interface. */
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 *iterpool;
  apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));

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

  if (! targets->nelts)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

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

  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));

  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));

  iterpool = svn_pool_create(pool);
  for (i = 0; i < targets->nelts; i++)
    {
      const char *target = APR_ARRAY_IDX(targets, i, const char *);

      svn_pool_clear(iterpool);
      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
      SVN_ERR(svn_cl__try
              (svn_client_add5(target,
                               opt_state->depth,
                               opt_state->force, opt_state->no_ignore,
                               opt_state->no_autoprops, opt_state->parents,
                               ctx, iterpool),
               errors, opt_state->quiet,
               SVN_ERR_ENTRY_EXISTS,
               SVN_ERR_WC_PATH_NOT_FOUND,
               SVN_NO_ERROR));
    }

  svn_pool_destroy(iterpool);

  if (errors->nelts > 0)
    {
      svn_error_t *err;

      err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
      for (i = 0; i < errors->nelts; i++)
        {
          apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
          if (status == SVN_ERR_WC_PATH_NOT_FOUND)
            err = svn_error_quick_wrap(err,
                                       _("Could not add all targets because "
                                         "some targets don't exist"));
          else if (status == SVN_ERR_ENTRY_EXISTS)
            err = svn_error_quick_wrap(err,
                                       _("Could not add all targets because "
                                         "some targets are already versioned"));
        }

      return svn_error_trace(err);
    }

  return SVN_NO_ERROR;
}
Пример #21
0
/* Drive EDITOR to affect the change represented by OPERATION.  HEAD
   is the last-known youngest revision in the repository. */
static svn_error_t *
drive(struct operation *operation,
      svn_revnum_t head,
      const svn_delta_editor_t *editor,
      apr_pool_t *pool)
{
  apr_pool_t *subpool = svn_pool_create(pool);
  apr_hash_index_t *hi;
  struct driver_state state;
  for (hi = apr_hash_first(pool, operation->children);
       hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      struct operation *child;
      void *file_baton = NULL;

      svn_pool_clear(subpool);
      apr_hash_this(hi, &key, NULL, &val);
      child = val;

      /* Deletes and replacements are simple -- delete something. */
      if (child->operation == OP_DELETE || child->operation == OP_REPLACE)
        {
          SVN_ERR(editor->delete_entry(key, head, operation->baton, subpool));
        }
      /* Opens could be for directories or files. */
      if (child->operation == OP_OPEN)
        {
          if (child->kind == svn_node_dir)
            {
              SVN_ERR(editor->open_directory(key, operation->baton, head,
                                             subpool, &child->baton));
            }
          else
            {
              SVN_ERR(editor->open_file(key, operation->baton, head,
                                        subpool, &file_baton));
            }
        }
      /* Adds and replacements could also be for directories or files. */
      if (child->operation == OP_ADD || child->operation == OP_REPLACE
          || child->operation == OP_PROPSET)
        {
          if (child->kind == svn_node_dir)
            {
              SVN_ERR(editor->add_directory(key, operation->baton,
                                            child->url, child->rev,
                                            subpool, &child->baton));
            }
          else
            {
              SVN_ERR(editor->add_file(key, operation->baton, child->url,
                                       child->rev, subpool, &file_baton));
            }
        }
      /* If there's a source file and an open file baton, we get to
         change textual contents. */
      if ((child->src_file) && (file_baton))
        {
          svn_txdelta_window_handler_t handler;
          void *handler_baton;
          svn_stream_t *contents;
          apr_file_t *f = NULL;

          SVN_ERR(editor->apply_textdelta(file_baton, NULL, subpool,
                                          &handler, &handler_baton));
          if (strcmp(child->src_file, "-"))
            {
              SVN_ERR(svn_io_file_open(&f, child->src_file, APR_READ,
                                       APR_OS_DEFAULT, pool));
            }
          else
            {
              apr_status_t apr_err = apr_file_open_stdin(&f, pool);
              if (apr_err)
                return svn_error_wrap_apr(apr_err, "Can't open stdin");
            }
          contents = svn_stream_from_aprfile(f, pool);
          SVN_ERR(svn_txdelta_send_stream(contents, handler,
                                          handler_baton, NULL, pool));
          SVN_ERR(svn_io_file_close(f, pool));
        }
      /* If we opened a file, we need to apply outstanding propmods,
         then close it. */
      if (file_baton)
        {
          if ((child->kind == svn_node_file)
              && (! apr_is_empty_table(child->props)))
            {
              state.baton = file_baton;
              state.pool = subpool;
              state.editor = editor;
              state.kind = child->kind;
              if (! apr_table_do(set_props, &state, child->props, NULL))
                SVN_ERR(state.err);
            }
          SVN_ERR(editor->close_file(file_baton, NULL, subpool));
        }
      /* If we opened, added, or replaced a directory, we need to
         recurse, apply outstanding propmods, and then close it. */
      if ((child->kind == svn_node_dir)
          && (child->operation == OP_OPEN
              || child->operation == OP_ADD
              || child->operation == OP_REPLACE))
        {
          SVN_ERR(drive(child, head, editor, subpool));
          if ((child->kind == svn_node_dir)
              && (! apr_is_empty_table(child->props)))
            {
              state.baton = child->baton;
              state.pool = subpool;
              state.editor = editor;
              state.kind = child->kind;
              if (! apr_table_do(set_props, &state, child->props, NULL))
                SVN_ERR(state.err);
            }
          SVN_ERR(editor->close_directory(child->baton, subpool));
        }
    }
  svn_pool_destroy(subpool);
  return SVN_NO_ERROR;
}
Пример #22
0
svn_error_t *
svn_wc_relocate3(const char *path,
                 svn_wc_adm_access_t *adm_access,
                 const char *from,
                 const char *to,
                 svn_boolean_t recurse,
                 svn_wc_relocation_validator3_t validator,
                 void *validator_baton,
                 apr_pool_t *pool)
{
  apr_hash_t *entries;
  apr_hash_index_t *hi;
  const svn_wc_entry_t *entry;
  apr_pool_t *subpool;

  SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, pool));
  if (! entry)
    return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, NULL, NULL);

  if (entry->kind == svn_node_file)
    {
      SVN_ERR(relocate_entry(adm_access, entry, from, to,
                             validator, validator_baton, TRUE /* sync */,
                             pool));
      return SVN_NO_ERROR;
    }

  /* Relocate THIS_DIR first, in order to pre-validate the relocated URL
     of all of the other entries.  This is technically cheating because
     it relies on knowledge of the libsvn_client implementation, but it
     significantly cuts down on the number of expensive validations the
     validator has to do.  ### Should svn_wc.h document the ordering? */
  SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool));
  entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING);
  SVN_ERR(relocate_entry(adm_access, entry, from, to,
                         validator, validator_baton, FALSE, pool));

  subpool = svn_pool_create(pool);

  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;

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

      if (strcmp(key, SVN_WC_ENTRY_THIS_DIR) == 0)
        continue;

      svn_pool_clear(subpool);

      if (recurse && (entry->kind == svn_node_dir)
          && (! entry->deleted || (entry->schedule == svn_wc_schedule_add))
          && ! entry->absent)
        {
          svn_wc_adm_access_t *subdir_access;
          const char *subdir = svn_path_join(path, key, subpool);
          if (svn_wc__adm_missing(adm_access, subdir))
            continue;
          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access,
                                      subdir, subpool));
          SVN_ERR(svn_wc_relocate3(subdir, subdir_access, from, to,
                                   recurse, validator,
                                   validator_baton, subpool));
        }
      SVN_ERR(relocate_entry(adm_access, entry, from, to,
                             validator, validator_baton, FALSE, subpool));
    }

  svn_pool_destroy(subpool);

  SVN_ERR(svn_wc__props_delete(path, svn_wc__props_wcprop, adm_access, pool));
  SVN_ERR(svn_wc__entries_write(entries, adm_access, pool));
  return SVN_NO_ERROR;
}
Пример #23
0
/* Prepare LINE for display, pruning or extending it to an appropriate
 * display width, and stripping the EOL marker, if any.
 * This function assumes that the data in LINE is encoded in UTF-8. */
static const char *
prepare_line_for_display(const char *line, apr_pool_t *pool)
{
  svn_stringbuf_t *buf = svn_stringbuf_create(line, pool);
  size_t width;
  size_t line_width = LINE_DISPLAY_WIDTH;
  apr_pool_t *iterpool;

  /* Trim EOL. */
  if (buf->len >= 2 &&
      buf->data[buf->len - 2] == '\r' &&
      buf->data[buf->len - 1] == '\n')
    svn_stringbuf_chop(buf, 2);
  else if (buf->len >= 1 &&
           (buf->data[buf->len - 1] == '\n' ||
            buf->data[buf->len - 1] == '\r'))
    svn_stringbuf_chop(buf, 1);

  /* Determine the on-screen width of the line. */
  width = svn_utf_cstring_utf8_width(buf->data);
  if (width == -1)
    {
      /* Determining the width failed. Try to get rid of unprintable
       * characters in the line buffer. */
      buf = svn_stringbuf_create(svn_xml_fuzzy_escape(buf->data, pool), pool);
      width = svn_utf_cstring_utf8_width(buf->data);
      if (width == -1)
        width = buf->len; /* fallback: buffer length */
    }

  /* Trim further in case line is still too long, or add padding in case
   * it is too short. */
  iterpool = svn_pool_create(pool);
  while (width > line_width)
    {
      const char *last_valid;

      svn_pool_clear(iterpool);

      svn_stringbuf_chop(buf, 1);

      /* Be careful not to invalidate the UTF-8 string by trimming
       * just part of a character. */
      last_valid = svn_utf__last_valid(buf->data, buf->len);
      if (last_valid < buf->data + buf->len)
        svn_stringbuf_chop(buf, (buf->data + buf->len) - last_valid);

      width = svn_utf_cstring_utf8_width(buf->data);
      if (width == -1)
        width = buf->len; /* fallback: buffer length */
    }
  svn_pool_destroy(iterpool);

  while (width == 0 || width < line_width)
    {
      svn_stringbuf_appendbyte(buf, ' ');
      width++;
    }

  SVN_ERR_ASSERT_NO_RETURN(width == line_width);
  return buf->data;
}
Пример #24
0
svn_error_t *
svn_fs_bdb__get_txn_list(apr_array_header_t **names_p,
                         svn_fs_t *fs,
                         trail_t *trail,
                         apr_pool_t *pool)
{
  base_fs_data_t *bfd = fs->fsap_data;
  apr_size_t const next_key_key_len = strlen(NEXT_KEY_KEY);
  apr_pool_t *subpool = svn_pool_create(pool);
  apr_array_header_t *names;
  DBC *cursor;
  DBT key, value;
  int db_err, db_c_err;

  /* Allocate the initial names array */
  names = apr_array_make(pool, 4, sizeof(const char *));

  /* Create a database cursor to list the transaction names. */
  svn_fs_base__trail_debug(trail, "transactions", "cursor");
  SVN_ERR(BDB_WRAP(fs, "reading transaction list (opening cursor)",
                   bfd->transactions->cursor(bfd->transactions,
                                             trail->db_txn, &cursor, 0)));

  /* Build a null-terminated array of keys in the transactions table. */
  for (db_err = svn_bdb_dbc_get(cursor,
                                svn_fs_base__result_dbt(&key),
                                svn_fs_base__result_dbt(&value),
                                DB_FIRST);
       db_err == 0;
       db_err = svn_bdb_dbc_get(cursor,
                                svn_fs_base__result_dbt(&key),
                                svn_fs_base__result_dbt(&value),
                                DB_NEXT))
    {
      transaction_t *txn;
      svn_skel_t *txn_skel;
      svn_error_t *err;

      /* Clear the per-iteration subpool */
      svn_pool_clear(subpool);

      /* Track the memory alloc'd for fetching the key and value here
         so that when the containing pool is cleared, this memory is
         freed. */
      svn_fs_base__track_dbt(&key, subpool);
      svn_fs_base__track_dbt(&value, subpool);

      /* Ignore the "next-key" key. */
      if (key.size == next_key_key_len
          && 0 == memcmp(key.data, NEXT_KEY_KEY, next_key_key_len))
        continue;

      /* Parse TRANSACTION skel */
      txn_skel = svn_skel__parse(value.data, value.size, subpool);
      if (! txn_skel)
        {
          svn_bdb_dbc_close(cursor);
          return svn_fs_base__err_corrupt_txn
            (fs, apr_pstrmemdup(pool, key.data, key.size));
        }

      /* Convert skel to native type. */
      if ((err = svn_fs_base__parse_transaction_skel(&txn, txn_skel,
                                                     subpool)))
        {
          svn_bdb_dbc_close(cursor);
          return err;
        }

      /* If this is an immutable "committed" transaction, ignore it. */
      if (is_committed(txn))
        continue;

      /* Add the transaction name to the NAMES array, duping it into POOL. */
      APR_ARRAY_PUSH(names, const char *) = apr_pstrmemdup(pool, key.data,
                                                           key.size);
    }

  /* Check for errors, but close the cursor first. */
  db_c_err = svn_bdb_dbc_close(cursor);
  if (db_err != DB_NOTFOUND)
    {
      SVN_ERR(BDB_WRAP(fs, "reading transaction list (listing keys)",
                       db_err));
    }
  SVN_ERR(BDB_WRAP(fs, "reading transaction list (closing cursor)",
                   db_c_err));

  /* Destroy the per-iteration subpool */
  svn_pool_destroy(subpool);

  *names_p = names;
  return SVN_NO_ERROR;
}
Пример #25
0
/* Merge chunks CHUNK1 and CHUNK2.
 * Each lines array contains elements of type svn_stringbuf_t*.
 * Return the result in *MERGED_CHUNK, or set *MERGED_CHUNK to NULL in
 * case the user chooses to postpone resolution of this chunk.
 * If the user wants to abort the merge, set *ABORT_MERGE to TRUE. */
static svn_error_t *
merge_chunks(apr_array_header_t **merged_chunk,
             svn_boolean_t *abort_merge,
             apr_array_header_t *chunk1,
             apr_array_header_t *chunk2,
             svn_linenum_t current_line1,
             svn_linenum_t current_line2,
             const char *editor_cmd,
             apr_hash_t *config,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
{
  svn_stringbuf_t *prompt;
  int i;
  int max_chunk_lines;
  apr_pool_t *iterpool;

  max_chunk_lines = chunk1->nelts > chunk2->nelts ? chunk1->nelts
                                                  : chunk2->nelts;
  *abort_merge = FALSE;

  /*
   * Prepare the selection prompt.
   */

  prompt = svn_stringbuf_create(
             apr_psprintf(scratch_pool, "%s\n%s|%s\n%s",
                          _("Conflicting section found during merge:"),
                          prepare_line_for_display(
                            apr_psprintf(scratch_pool,
                                         _("(1) their version (at line %lu)"),
                                         current_line1),
                            scratch_pool),
                          prepare_line_for_display(
                            apr_psprintf(scratch_pool,
                                         _("(2) your version (at line %lu)"),
                                         current_line2),
                            scratch_pool),
                          get_sep_string(scratch_pool)),
             scratch_pool);

  iterpool = svn_pool_create(scratch_pool);
  for (i = 0; i < max_chunk_lines; i++)
    {
      const char *line1;
      const char *line2;
      const char *prompt_line;

      svn_pool_clear(iterpool);

      if (i < chunk1->nelts)
        {
          svn_stringbuf_t *line_utf8;

          SVN_ERR(svn_utf_stringbuf_to_utf8(&line_utf8,
                                            APR_ARRAY_IDX(chunk1, i,
                                                          svn_stringbuf_t*),
                                            iterpool));
          line1 = prepare_line_for_display(line_utf8->data, iterpool);
        }
      else
Пример #26
0
/* ### TODO: Handle depth. */
static svn_error_t *
diff_deleted_dir(const char *dir,
                 svn_revnum_t revision,
                 svn_ra_session_t *ra_session,
                 void *edit_baton,
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
                 apr_pool_t *pool)
{
  struct edit_baton *eb = edit_baton;
  apr_hash_t *dirents;
  apr_pool_t *iterpool = svn_pool_create(pool);
  apr_hash_index_t *hi;

  if (cancel_func)
    SVN_ERR(cancel_func(cancel_baton));

  SVN_ERR(svn_ra_get_dir2(ra_session,
                          &dirents,
                          NULL, NULL,
                          dir,
                          revision,
                          SVN_DIRENT_KIND,
                          pool));

  for (hi = apr_hash_first(pool, dirents); hi;
       hi = apr_hash_next(hi))
    {
      const char *path;
      const char *name = svn__apr_hash_index_key(hi);
      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
      svn_node_kind_t kind;
      svn_client_diff_summarize_t *sum;

      svn_pool_clear(iterpool);

      path = svn_relpath_join(dir, name, iterpool);

      SVN_ERR(svn_ra_check_path(eb->ra_session,
                                path,
                                eb->revision,
                                &kind,
                                iterpool));

      sum = apr_pcalloc(iterpool, sizeof(*sum));
      sum->summarize_kind = svn_client_diff_summarize_kind_deleted;
      sum->path = path;
      sum->node_kind = kind;

      SVN_ERR(eb->summarize_func(sum,
                                 eb->summarize_func_baton,
                                 iterpool));

      if (dirent->kind == svn_node_dir)
        SVN_ERR(diff_deleted_dir(path,
                                 revision,
                                 ra_session,
                                 eb,
                                 cancel_func,
                                 cancel_baton,
                                 iterpool));
    }

  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
Пример #27
0
svn_error_t *
svn_client_upgrade(const char *path,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *scratch_pool)
{
  const char *local_abspath;
  apr_hash_t *externals;
  apr_hash_index_t *hi;
  apr_pool_t *iterpool;
  apr_pool_t *iterpool2;
  svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
  struct repos_info_baton info_baton;

  info_baton.state_pool = scratch_pool;
  info_baton.ctx = ctx;
  info_baton.last_repos = NULL;
  info_baton.last_uuid = NULL;

  if (svn_path_is_url(path))
    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                             _("'%s' is not a local path"), path);

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
  SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, local_abspath,
                         fetch_repos_info, &info_baton,
                         ctx->cancel_func, ctx->cancel_baton,
                         ctx->notify_func2, ctx->notify_baton2,
                         scratch_pool));

  /* Now it's time to upgrade the externals too. We do it after the wc
     upgrade to avoid that errors in the externals causes the wc upgrade to
     fail. Thanks to caching the performance penalty of walking the wc a
     second time shouldn't be too severe */
  SVN_ERR(svn_client_propget5(&externals, NULL, SVN_PROP_EXTERNALS,
                              local_abspath, &rev, &rev, NULL,
                              svn_depth_infinity, NULL, ctx,
                              scratch_pool, scratch_pool));

  iterpool = svn_pool_create(scratch_pool);
  iterpool2 = svn_pool_create(scratch_pool);

  for (hi = apr_hash_first(scratch_pool, externals); hi;
       hi = apr_hash_next(hi))
    {
      int i;
      const char *externals_parent_abspath;
      const char *externals_parent_url;
      const char *externals_parent_repos_root_url;
      const char *externals_parent_repos_relpath;
      const char *externals_parent = svn__apr_hash_index_key(hi);
      svn_string_t *external_desc = svn__apr_hash_index_val(hi);
      apr_array_header_t *externals_p;
      svn_error_t *err;

      svn_pool_clear(iterpool);
      externals_p = apr_array_make(iterpool, 1,
                                   sizeof(svn_wc_external_item2_t*));

      /* In this loop, an error causes the respective externals definition, or
       * the external (inner loop), to be skipped, so that upgrade carries on
       * with the other externals. */

      err = svn_dirent_get_absolute(&externals_parent_abspath,
                                    externals_parent, iterpool);

      if (!err)
        err = svn_wc__node_get_repos_info(NULL,
                                          &externals_parent_repos_relpath,
                                          &externals_parent_repos_root_url,
                                          NULL,
                                          ctx->wc_ctx,
                                          externals_parent_abspath,
                                          iterpool, iterpool);

      if (!err)
        externals_parent_url = svn_path_url_add_component2(
                                    externals_parent_repos_root_url,
                                    externals_parent_repos_relpath,
                                    iterpool);
      if (!err)
        err = svn_wc_parse_externals_description3(
                  &externals_p, svn_dirent_dirname(path, iterpool),
                  external_desc->data, FALSE, iterpool);
      if (err)
        {
          svn_wc_notify_t *notify =
              svn_wc_create_notify(externals_parent,
                                   svn_wc_notify_failed_external,
                                   scratch_pool);
          notify->err = err;

          ctx->notify_func2(ctx->notify_baton2,
                            notify, scratch_pool);

          svn_error_clear(err);

          /* Next externals definition, please... */
          continue;
        }

      for (i = 0; i < externals_p->nelts; i++)
        {
          svn_wc_external_item2_t *item;
          const char *resolved_url;
          const char *external_abspath;
          const char *repos_relpath;
          const char *repos_root_url;
          const char *repos_uuid;
          svn_node_kind_t external_kind;
          svn_revnum_t peg_revision;
          svn_revnum_t revision;

          item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);

          svn_pool_clear(iterpool2);
          external_abspath = svn_dirent_join(externals_parent_abspath,
                                             item->target_dir,
                                             iterpool2);

          err = svn_wc__resolve_relative_external_url(
                                              &resolved_url,
                                              item,
                                              externals_parent_repos_root_url,
                                              externals_parent_url,
                                              scratch_pool, scratch_pool);
          if (err)
            goto handle_error;

          /* This is a hack. We only need to call svn_wc_upgrade() on external
           * dirs, as file externals are upgraded along with their defining
           * WC.  Reading the kind will throw an exception on an external dir,
           * saying that the wc must be upgraded.  If it's a file, the lookup
           * is done in an adm_dir belonging to the defining wc (which has
           * already been upgraded) and no error is returned.  If it doesn't
           * exist (external that isn't checked out yet), we'll just get
           * svn_node_none. */
          err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx,
                                  external_abspath, TRUE, FALSE, iterpool2);
          if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
            {
              svn_error_clear(err);

              err = svn_client_upgrade(external_abspath, ctx, iterpool2);
              if (err)
                goto handle_error;
            }
          else if (err)
            goto handle_error;

          /* The upgrade of any dir should be done now, get the now reliable
           * kind. */
          err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx, external_abspath,
                                  TRUE, FALSE, iterpool2);
          if (err)
            goto handle_error;

          /* Update the EXTERNALS table according to the root URL,
           * relpath and uuid known in the upgraded external WC. */

          /* We should probably have a function that provides all three
           * of root URL, repos relpath and uuid at once, but here goes... */

          /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
           * when the node is not present in the file system.
           * svn_wc__node_get_repos_info() would try to derive the URL. */
          err = svn_wc__node_get_repos_info(NULL,
                                            &repos_relpath,
                                            &repos_root_url,
                                            &repos_uuid,
                                            ctx->wc_ctx,
                                            external_abspath,
                                            iterpool2, iterpool2);
          if (err)
            goto handle_error;

          /* If we haven't got any information from the checked out external,
           * or if the URL information mismatches the external's definition,
           * ask fetch_repos_info() to find out the repos root. */
          if (0 != strcmp(resolved_url,
                          svn_path_url_add_component2(repos_root_url,
                                                      repos_relpath,
                                                      scratch_pool)))
            {
              err = fetch_repos_info(&repos_root_url,
                                     &repos_uuid,
                                     &info_baton,
                                     resolved_url,
                                     scratch_pool, scratch_pool);
              if (err)
                goto handle_error;

              repos_relpath = svn_uri_skip_ancestor(repos_root_url,
                                                    resolved_url,
                                                    iterpool2);

              /* There's just the URL, no idea what kind the external is.
               * That's fine, as the external isn't even checked out yet.
               * The kind will be set during the next 'update'. */
              external_kind = svn_node_unknown;
            }

          if (err)
            goto handle_error;

          peg_revision = (item->peg_revision.kind == svn_opt_revision_number
                          ? item->peg_revision.value.number
                          : SVN_INVALID_REVNUM);

          revision = (item->revision.kind == svn_opt_revision_number
                      ? item->revision.value.number
                      : SVN_INVALID_REVNUM);

          err = svn_wc__upgrade_add_external_info(ctx->wc_ctx,
                                                  external_abspath,
                                                  external_kind,
                                                  externals_parent,
                                                  repos_relpath,
                                                  repos_root_url,
                                                  repos_uuid,
                                                  peg_revision,
                                                  revision,
                                                  iterpool2);
handle_error:
          if (err)
            {
              svn_wc_notify_t *notify =
                  svn_wc_create_notify(external_abspath,
                                       svn_wc_notify_failed_external,
                                       scratch_pool);
              notify->err = err;
              ctx->notify_func2(ctx->notify_baton2,
                                notify, scratch_pool);
              svn_error_clear(err);
              /* Next external node, please... */
            }
        }
    }

  svn_pool_destroy(iterpool);
  svn_pool_destroy(iterpool2);

  return SVN_NO_ERROR;
}
Пример #28
0
/* Read CONTENT_LENGTH bytes from STREAM, parsing the bytes as an
   encoded Subversion properties hash, and making multiple calls to
   PARSE_FNS->set_*_property on RECORD_BATON (depending on the value
   of IS_NODE.)

   Set *ACTUAL_LENGTH to the number of bytes consumed from STREAM.
   If an error is returned, the value of *ACTUAL_LENGTH is undefined.

   Use POOL for all allocations.  */
static svn_error_t *
parse_property_block(svn_stream_t *stream,
                     svn_filesize_t content_length,
                     const svn_repos_parse_fns3_t *parse_fns,
                     void *record_baton,
                     void *parse_baton,
                     svn_boolean_t is_node,
                     svn_filesize_t *actual_length,
                     apr_pool_t *pool)
{
  svn_stringbuf_t *strbuf;
  apr_pool_t *proppool = svn_pool_create(pool);

  *actual_length = 0;
  while (content_length != *actual_length)
    {
      char *buf;  /* a pointer into the stringbuf's data */
      svn_boolean_t eof;

      svn_pool_clear(proppool);

      /* Read a key length line.  (Actually, it might be PROPS_END). */
      SVN_ERR(svn_stream_readline(stream, &strbuf, "\n", &eof, proppool));

      if (eof)
        {
          /* We could just use stream_ran_dry() or stream_malformed(),
             but better to give a non-generic property block error. */
          return svn_error_create
            (SVN_ERR_STREAM_MALFORMED_DATA, NULL,
             _("Incomplete or unterminated property block"));
        }

      *actual_length += (strbuf->len + 1); /* +1 because we read a \n too. */
      buf = strbuf->data;

      if (! strcmp(buf, "PROPS-END"))
        break; /* no more properties. */

      else if ((buf[0] == 'K') && (buf[1] == ' '))
        {
          char *keybuf;
          apr_uint64_t len;

          SVN_ERR(svn_cstring_strtoui64(&len, buf + 2, 0, APR_SIZE_MAX, 10));
          SVN_ERR(read_key_or_val(&keybuf, actual_length,
                                  stream, (apr_size_t)len, proppool));

          /* Read a val length line */
          SVN_ERR(svn_stream_readline(stream, &strbuf, "\n", &eof, proppool));
          if (eof)
            return stream_ran_dry();

          *actual_length += (strbuf->len + 1); /* +1 because we read \n too */
          buf = strbuf->data;

          if ((buf[0] == 'V') && (buf[1] == ' '))
            {
              svn_string_t propstring;
              char *valbuf;
              apr_int64_t val;

              SVN_ERR(svn_cstring_atoi64(&val, buf + 2));
              propstring.len = (apr_size_t)val;
              SVN_ERR(read_key_or_val(&valbuf, actual_length,
                                      stream, propstring.len, proppool));
              propstring.data = valbuf;

              /* Now, send the property pair to the vtable! */
              if (is_node)
                {
                  SVN_ERR(parse_fns->set_node_property(record_baton,
                                                       keybuf,
                                                       &propstring));
                }
              else
                {
                  SVN_ERR(parse_fns->set_revision_property(record_baton,
                                                           keybuf,
                                                           &propstring));
                }
            }
          else
            return stream_malformed(); /* didn't find expected 'V' line */
        }
      else if ((buf[0] == 'D') && (buf[1] == ' '))
        {
          char *keybuf;
          apr_uint64_t len;

          SVN_ERR(svn_cstring_strtoui64(&len, buf + 2, 0, APR_SIZE_MAX, 10));
          SVN_ERR(read_key_or_val(&keybuf, actual_length,
                                  stream, (apr_size_t)len, proppool));

          /* We don't expect these in revision properties, and if we see
             one when we don't have a delete_node_property callback,
             then we're seeing a v3 feature in a v2 dump. */
          if (!is_node || !parse_fns->delete_node_property)
            return stream_malformed();

          SVN_ERR(parse_fns->delete_node_property(record_baton, keybuf));
        }
      else
        return stream_malformed(); /* didn't find expected 'K' line */

    } /* while (1) */

  svn_pool_destroy(proppool);
  return SVN_NO_ERROR;
}
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__proplist(apr_getopt_t *os,
                 void *baton,
                 apr_pool_t *scratch_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;

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

  /* Add "." if user passed 0 file arguments */
  svn_opt_push_implicit_dot_target(targets, scratch_pool);

  if (opt_state->revprop)  /* operate on revprops */
    {
      svn_revnum_t rev;
      const char *URL;
      apr_hash_t *proplist;

      SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets,
                                      &URL, ctx, scratch_pool));

      /* Let libsvn_client do the real work. */
      SVN_ERR(svn_client_revprop_list(&proplist,
                                      URL, &(opt_state->start_revision),
                                      &rev, ctx, scratch_pool));

      if (opt_state->xml)
        {
          svn_stringbuf_t *sb = NULL;
          char *revstr = apr_psprintf(scratch_pool, "%ld", rev);

          SVN_ERR(svn_cl__xml_print_header("properties", scratch_pool));

          svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal,
                                "revprops",
                                "rev", revstr, NULL);
          SVN_ERR(svn_cl__print_xml_prop_hash
                  (&sb, proplist, (! opt_state->verbose), scratch_pool));
          svn_xml_make_close_tag(&sb, scratch_pool, "revprops");

          SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
          SVN_ERR(svn_cl__xml_print_footer("properties", scratch_pool));
        }
      else
        {
          SVN_ERR
            (svn_cmdline_printf(scratch_pool,
                                _("Unversioned properties on revision %ld:\n"),
                                rev));

          SVN_ERR(svn_cl__print_prop_hash
                  (NULL, proplist, (! opt_state->verbose), scratch_pool));
        }
    }
  else  /* operate on normal, versioned properties (not revprops) */
    {
      int i;
      apr_pool_t *iterpool;
      svn_proplist_receiver_t pl_receiver;
      svn_boolean_t had_errors = FALSE;

      if (opt_state->xml)
        {
          SVN_ERR(svn_cl__xml_print_header("properties", scratch_pool));
          pl_receiver = proplist_receiver_xml;
        }
      else
        {
          pl_receiver = proplist_receiver;
        }

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

      iterpool = svn_pool_create(scratch_pool);
      for (i = 0; i < targets->nelts; i++)
        {
          const char *target = APR_ARRAY_IDX(targets, i, const char *);
          proplist_baton_t pl_baton;
          const char *truepath;
          svn_opt_revision_t peg_revision;
          svn_boolean_t success;

          svn_pool_clear(iterpool);
          SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

          pl_baton.is_url = svn_path_is_url(target);
          pl_baton.opt_state = opt_state;

          /* Check for a peg revision. */
          SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
                                     iterpool));

          SVN_ERR(svn_cl__try(
                   svn_client_proplist3(truepath, &peg_revision,
                                        &(opt_state->start_revision),
                                        opt_state->depth,
                                        opt_state->changelists,
                                        pl_receiver, &pl_baton,
                                        ctx, iterpool),
                   &success, opt_state->quiet,
                   SVN_ERR_UNVERSIONED_RESOURCE,
                   SVN_ERR_ENTRY_NOT_FOUND,
                   SVN_NO_ERROR));

          if (!success)
            had_errors = TRUE;
        }
      svn_pool_destroy(iterpool);

      if (opt_state->xml)
        SVN_ERR(svn_cl__xml_print_footer("properties", scratch_pool));

      /* Error out *after* we closed the XML element */
      if (had_errors)
        return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
                                _("Could not display info for all targets "
                                  "because some targets don't exist"));
    }

  return SVN_NO_ERROR;
}
Пример #30
0
svn_error_t *
svn_ra_neon__do_proppatch(svn_ra_neon__session_t *ras,
                          const char *url,
                          apr_hash_t *prop_changes,
                          apr_array_header_t *prop_deletes,
                          apr_hash_t *extra_headers,
                          apr_pool_t *pool)
{
  svn_error_t *err;
  svn_stringbuf_t *body;
  apr_pool_t *subpool = svn_pool_create(pool);

  /* just punt if there are no changes to make. */
  if ((prop_changes == NULL || (! apr_hash_count(prop_changes)))
      && (prop_deletes == NULL || prop_deletes->nelts == 0))
    return SVN_NO_ERROR;

  /* easier to roll our own PROPPATCH here than use ne_proppatch(), which
   * doesn't really do anything clever. */
  body = svn_stringbuf_create
    ("<?xml version=\"1.0\" encoding=\"utf-8\" ?>" DEBUG_CR
     "<D:propertyupdate xmlns:D=\"DAV:\" xmlns:V=\""
     SVN_DAV_PROP_NS_DAV "\" xmlns:C=\""
     SVN_DAV_PROP_NS_CUSTOM "\" xmlns:S=\""
     SVN_DAV_PROP_NS_SVN "\">" DEBUG_CR, pool);

  /* Handle property changes. */
  if (prop_changes)
    {
      apr_hash_index_t *hi;
      svn_stringbuf_appendcstr(body, "<D:set><D:prop>");
      for (hi = apr_hash_first(pool, prop_changes); hi; hi = apr_hash_next(hi))
        {
          const void *key;
          void *val;
          svn_pool_clear(subpool);
          apr_hash_this(hi, &key, NULL, &val);
          append_setprop(body, key, val, subpool);
        }
      svn_stringbuf_appendcstr(body, "</D:prop></D:set>");
    }

  /* Handle property deletions. */
  if (prop_deletes)
    {
      int n;
      svn_stringbuf_appendcstr(body, "<D:remove><D:prop>");
      for (n = 0; n < prop_deletes->nelts; n++)
        {
          const char *name = APR_ARRAY_IDX(prop_deletes, n, const char *);
          svn_pool_clear(subpool);
          append_setprop(body, name, NULL, subpool);
        }
      svn_stringbuf_appendcstr(body, "</D:prop></D:remove>");
    }
  svn_pool_destroy(subpool);

  /* Finish up the body. */
  svn_stringbuf_appendcstr(body, "</D:propertyupdate>");

  /* Finish up the headers. */
  if (! extra_headers)
    extra_headers = apr_hash_make(pool);
  apr_hash_set(extra_headers, "Content-Type", APR_HASH_KEY_STRING,
               "text/xml; charset=UTF-8");

  err = svn_ra_neon__simple_request(NULL, ras, "PROPPATCH", url,
                                    extra_headers, body->data,
                                    200, 207, pool);
  if (err)
    return svn_error_create
      (SVN_ERR_RA_DAV_PROPPATCH_FAILED, err,
       _("At least one property change failed; repository is unchanged"));

  return SVN_NO_ERROR;
}