Esempio n. 1
0
/* APR cleanup function used to close the database when its pool is destroyed.
   DATA should be the svn_sqlite__db_t handle for the database. */
static apr_status_t
close_apr(void *data)
{
  svn_sqlite__db_t *db = data;
  svn_error_t *err = SVN_NO_ERROR;
  apr_status_t result;
  int i;

  /* Check to see if we've already closed this database. */
  if (db->db3 == NULL)
    return APR_SUCCESS;

  /* Finalize any prepared statements. */
  if (db->prepared_stmts)
    {
      for (i = 0; i < db->nbr_statements + STMT_INTERNAL_LAST; i++)
        {
          if (db->prepared_stmts[i])
            {
              if (i < db->nbr_statements
                  && db->prepared_stmts[i]->needs_reset)
                {
#ifdef SVN_DEBUG
                  const char *stmt_text = db->statement_strings[i];
                  SVN_UNUSED(stmt_text);

                  SVN_ERR_MALFUNCTION_NO_RETURN();
#else
                  err = svn_error_compose_create(err,
                            svn_sqlite__reset(db->prepared_stmts[i]));
#endif
                }
              err = svn_error_compose_create(
                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
            }
        }
    }

  result = sqlite3_close(db->db3);

  /* If there's a pre-existing error, return it. */
  if (err)
    {
      result = err->apr_err;
      svn_error_clear(err);
      return result;
    }

  if (result != SQLITE_OK)
    return SQLITE_ERROR_CODE(result); /* ### lossy */

  db->db3 = NULL;

  return APR_SUCCESS;
}
Esempio n. 2
0
svn_error_t *
svn_sqlite__finish_savepoint(svn_sqlite__db_t *db,
                             svn_error_t *err)
{
  svn_sqlite__stmt_t *stmt;

  if (err)
    {
      svn_error_t *err2;

      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_ROLLBACK_TO_SAVEPOINT_SVN);

      if (!err2)
        {
          err2 = svn_error_trace(svn_sqlite__step_done(stmt));

          if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
            {
              /* Ok, we have a major problem. Some statement is still open,
                 which makes it impossible to release this savepoint.

                 ### See huge comment in rollback_transaction() for
                     further details */

              err2 = svn_error_trace(reset_all_statements(db, err2));
              err2 = svn_error_compose_create(
                          svn_error_trace(svn_sqlite__step_done(stmt)),
                          err2);
            }
        }

      err = svn_error_compose_create(err, err2);
      err2 = get_internal_statement(&stmt, db,
                                    STMT_INTERNAL_RELEASE_SAVEPOINT_SVN);

      if (!err2)
        err2 = svn_error_trace(svn_sqlite__step_done(stmt));

      return svn_error_compose_create(err, err2);
    }

  SVN_ERR(get_internal_statement(&stmt, db,
                                 STMT_INTERNAL_RELEASE_SAVEPOINT_SVN));

  /* ### Releasing a savepoint can fail and leave the db connection
         unusable; see svn_sqlite__finish_transaction(). */
  return svn_error_trace(svn_sqlite__step_done(stmt));
}
Esempio n. 3
0
static svn_error_t *
rollback_transaction(svn_sqlite__db_t *db,
                     svn_error_t *error_to_wrap)
{
  svn_sqlite__stmt_t *stmt;
  svn_error_t *err;

  err = get_internal_statement(&stmt, db, STMT_INTERNAL_ROLLBACK_TRANSACTION);
  if (!err)
    {
      err = svn_error_trace(svn_sqlite__step_done(stmt));

      if (err && err->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* ### Houston, we have a problem!

             We are trying to rollback but we can't because some
             statements are still busy. This leaves the database
             unusable for future transactions as the current transaction
             is still open.

             As we are returning the actual error as the most relevant
             error in the chain, our caller might assume that it can
             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
             in fact the SQLite database is unusable until the statements
             started within this transaction are reset and the transaction
             aborted.

             We try to compensate by resetting all prepared but unreset
             statements; but we leave the busy error in the chain anyway to
             help diagnosing the original error and help in finding where
             a reset statement is missing. */
          err = svn_error_trace(reset_all_statements(db, err));
          err = svn_error_compose_create(
                      svn_error_trace(svn_sqlite__step_done(stmt)),
                      err);
        }
    }

  if (err)
    {
      /* Rollback failed, use a specific error code. */
      err = svn_error_create(SVN_SQLITE__ERR_ROLLBACK_FAILED, err,
                             _("SQLite transaction rollback failed"));
    }

  return svn_error_compose_create(error_to_wrap, err);
}
Esempio n. 4
0
/* The body of svn_sqlite__with_transaction() and
   svn_sqlite__with_immediate_transaction(), which see. */
static svn_error_t *
with_transaction(svn_sqlite__db_t *db,
                 svn_sqlite__transaction_callback_t cb_func,
                 void *cb_baton,
                 apr_pool_t *scratch_pool /* NULL allowed */)
{
  svn_error_t *err;

  err = cb_func(cb_baton, db, scratch_pool);

  /* Commit or rollback the sqlite transaction. */
  if (err)
    {
      svn_error_t *err2 = exec_sql(db, "ROLLBACK TRANSACTION;");

      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* ### Houston, we have a problem!

             We are trying to rollback but we can't because some
             statements are still busy. This leaves the database
             unusable for future transactions as the current transaction
             is still open.

             As we are returning the actual error as the most relevant
             error in the chain, our caller might assume that it can
             retry/compensate on this error (e.g. SVN_WC_LOCKED), while
             in fact the SQLite database is unusable until the statements
             started within this transaction are reset and the transaction
             aborted.

             We try to compensate by resetting all prepared but unreset
             statements; but we leave the busy error in the chain anyway to
             help diagnosing the original error and help in finding where
             a reset statement is missing. */

          err2 = reset_all_statements(db, err2);
          err2 = svn_error_compose_create(
                      exec_sql(db, "ROLLBACK TRANSACTION;"),
                      err2);
        }

      return svn_error_compose_create(err,
                                      err2);
    }

  return svn_error_trace(exec_sql(db, "COMMIT TRANSACTION;"));
}
Esempio n. 5
0
/* Remove all unreferenced pristines in the WC DB in WCROOT.
 *
 * Look for pristine texts whose 'refcount' in the DB is zero, and remove
 * them from the 'pristine' table and from disk.
 *
 * TODO: At least check that any zero refcount is really correct, before
 *       using it.  See dev@ email thread "Pristine text missing - cleanup
 *       doesn't work", <http://svn.haxx.se/dev/archive-2013-04/0426.shtml>.
 *
 * TODO: Ideas for possible extra clean-up operations:
 *
 *       * Check and correct all the refcounts.  Identify any rows missing
 *         from the 'pristine' table.  (Create a temporary index for speed
 *         if necessary?)
 *
 *       * Check the checksums.  (Very expensive to check them all, so find
 *         a way to not check them all.)
 *
 *       * Check for pristine files missing from disk but referenced in the
 *         'pristine' table.
 *
 *       * Repair any pristine files missing from disk and/or rows missing
 *         from the 'pristine' table and/or bad checksums.  Generally
 *         requires contacting the server, so requires support at a higher
 *         level than this function.
 *
 *       * Identify any pristine text files on disk that are not referenced
 *         in the DB, and delete them.
 *
 * TODO: Provide feedback about any errors found and any corrections made.
 */
static svn_error_t *
pristine_cleanup_wcroot(svn_wc__db_wcroot_t *wcroot,
                        apr_pool_t *scratch_pool)
{
  svn_sqlite__stmt_t *stmt;
  svn_error_t *err = NULL;
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);

  /* Find each unreferenced pristine in the DB and remove it. */
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                    STMT_SELECT_UNREFERENCED_PRISTINES));
  while (! err)
    {
      svn_boolean_t have_row;
      const svn_checksum_t *sha1_checksum;

      svn_pool_clear(iterpool);

      SVN_ERR(svn_sqlite__step(&have_row, stmt));
      if (! have_row)
        break;

      SVN_ERR(svn_sqlite__column_checksum(&sha1_checksum, stmt, 0,
                                          iterpool));
      err = pristine_remove_if_unreferenced(wcroot, sha1_checksum,
                                            iterpool);
    }

  svn_pool_destroy(iterpool);

  return svn_error_trace(
      svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
Esempio n. 6
0
int
main(int argc, const char *argv[])
{
  apr_pool_t *pool;
  int exit_code = EXIT_SUCCESS;
  svn_error_t *err;

  /* Initialize the app. */
  if (svn_cmdline_init("svnraisetreeconflict", stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  /* Create our top-level pool.  Use a separate mutexless allocator,
   * given this application is single threaded.
   */
  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));

  err = sub_main(&exit_code, argc, argv, pool);

  /* Flush stdout and report if it fails. It would be flushed on exit anyway
     but this makes sure that output is not silently lost if it fails. */
  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));

  if (err)
    {
      exit_code = EXIT_FAILURE;
      svn_cmdline_handle_exit_error(err, NULL, "svnraisetreeconflict: ");
    }

  svn_pool_destroy(pool);
  return exit_code;
}
Esempio n. 7
0
svn_error_t *
svn_wc_create_tmp_file2(apr_file_t **fp,
                        const char **new_name,
                        const char *path,
                        svn_io_file_del_t delete_when,
                        apr_pool_t *pool)
{
  svn_wc__db_t *db;
  const char *local_abspath;
  const char *temp_dir;
  svn_error_t *err;

  SVN_ERR_ASSERT(fp || new_name);

  SVN_ERR(svn_wc__db_open(&db,
                          NULL /* config */,
                          TRUE /* auto_upgrade */,
                          TRUE /* enforce_empty_wq */,
                          pool, pool));

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  err = svn_wc__db_temp_wcroot_tempdir(&temp_dir, db, local_abspath,
                                       pool, pool);
  err = svn_error_compose_create(err, svn_wc__db_close(db));
  if (err)
    return svn_error_trace(err);

  SVN_ERR(svn_io_open_unique_file3(fp, new_name, temp_dir,
                                   delete_when, pool, pool));

  return SVN_NO_ERROR;
}
Esempio n. 8
0
/* APR cleanup function used to close the database when its pool is destoryed.
   DATA should be the svn_sqlite__db_t handle for the database. */
static apr_status_t
close_apr(void *data)
{
  svn_sqlite__db_t *db = data;
  svn_error_t *err = SVN_NO_ERROR;
  int result;
  int i;

  /* Finalize any existing prepared statements. */
  for (i = 0; i < db->nbr_statements; i++)
    {
      if (db->prepared_stmts[i])
        err = svn_error_compose_create(
                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
    }

  result = sqlite3_close(db->db3);

  /* If there's a pre-existing error, return it. */
  if (err)
    {
      result = err->apr_err;
      svn_error_clear(err);
      return result;
    }

  if (result != SQLITE_OK)
    return SQLITE_ERROR_CODE(result);

  return APR_SUCCESS;
}
Esempio n. 9
0
int
main(int argc, const char *argv[])
{
  apr_pool_t *pool;
  int exit_code = EXIT_SUCCESS;
  svn_error_t *err;

  /* Initialize the app.  Send all error messages to 'stderr'.  */
  if (svn_cmdline_init(argv[0], stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  pool = svn_pool_create(NULL);

  err = sub_main(&exit_code, argc, argv, pool);

  /* Flush stdout and report if it fails. It would be flushed on exit anyway
     but this makes sure that output is not silently lost if it fails. */
  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));

  if (err)
    {
      if (exit_code == 0)
        exit_code = EXIT_FAILURE;
      svn_cmdline_handle_exit_error(err, NULL, "svnauthz: ");
    }

  svn_pool_destroy(pool);
  return exit_code;
}
Esempio n. 10
0
svn_error_t *
sbox_wc_resolve(svn_test__sandbox_t *b, const char *path, svn_depth_t depth,
                svn_wc_conflict_choice_t conflict_choice)
{
  const char *lock_abspath;
  svn_error_t *err;

  SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, b->wc_ctx,
                                                 sbox_wc_path(b, path),
                                                 b->pool, b->pool));
  err = svn_wc__resolve_conflicts(b->wc_ctx, sbox_wc_path(b, path),
                                  depth,
                                  TRUE /* resolve_text */,
                                  "" /* resolve_prop (ALL props) */,
                                  TRUE /* resolve_tree */,
                                  conflict_choice,
                                  NULL, NULL, /* conflict func */
                                  NULL, NULL, /* cancellation */
                                  NULL, NULL, /* notification */
                                  b->pool);

  err = svn_error_compose_create(err, svn_wc__release_write_lock(b->wc_ctx,
                                                                 lock_abspath,
                                                                 b->pool));
  return err;
}
Esempio n. 11
0
svn_error_t *
svn_repos_fs_commit_txn(const char **conflict_p,
                        svn_repos_t *repos,
                        svn_revnum_t *new_rev,
                        svn_fs_txn_t *txn,
                        apr_pool_t *pool)
{
  svn_error_t *err, *err2;
  const char *txn_name;

  *new_rev = SVN_INVALID_REVNUM;

  /* Run pre-commit hooks. */
  SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
  SVN_ERR(svn_repos__hooks_pre_commit(repos, txn_name, pool));

  /* Commit. */
  err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
  if (! SVN_IS_VALID_REVNUM(*new_rev))
    return err;

  /* Run post-commit hooks. */
  if ((err2 = svn_repos__hooks_post_commit(repos, *new_rev, pool)))
    {
      err2 = svn_error_create
               (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err2,
                _("Commit succeeded, but post-commit hook failed"));
    }

  return svn_error_compose_create(err, err2);
}
Esempio n. 12
0
svn_error_t *
svn_repos_fs_begin_txn_for_commit2(svn_fs_txn_t **txn_p,
                                   svn_repos_t *repos,
                                   svn_revnum_t rev,
                                   apr_hash_t *revprop_table,
                                   apr_pool_t *pool)
{
  apr_array_header_t *revprops;
  const char *txn_name;
  svn_string_t *author = svn_hash_gets(revprop_table, SVN_PROP_REVISION_AUTHOR);
  apr_hash_t *hooks_env;
  svn_error_t *err;
  svn_fs_txn_t *txn;

  /* Parse the hooks-env file (if any). */
  SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
                                     pool, pool));

  /* Begin the transaction, ask for the fs to do on-the-fly lock checks.
     We fetch its name, too, so the start-commit hook can use it.  */
  SVN_ERR(svn_fs_begin_txn2(&txn, repos->fs, rev,
                            SVN_FS_TXN_CHECK_LOCKS, pool));
  err = svn_fs_txn_name(&txn_name, txn, pool);
  if (err)
    return svn_error_compose_create(err, svn_fs_abort_txn(txn, pool));

  /* We pass the revision properties to the filesystem by adding them
     as properties on the txn.  Later, when we commit the txn, these
     properties will be copied into the newly created revision. */
  revprops = svn_prop_hash_to_array(revprop_table, pool);
  err = svn_repos_fs_change_txn_props(txn, revprops, pool);
  if (err)
    return svn_error_compose_create(err, svn_fs_abort_txn(txn, pool));

  /* Run start-commit hooks. */
  err = svn_repos__hooks_start_commit(repos, hooks_env,
                                      author ? author->data : NULL,
                                      repos->client_capabilities, txn_name,
                                      pool);
  if (err)
    return svn_error_compose_create(err, svn_fs_abort_txn(txn, pool));

  /* We have API promise that *TXN_P is unaffected on faulure. */
  *txn_p = txn;
  return SVN_NO_ERROR;
}
Esempio n. 13
0
svn_error_t *
svn_repos_fs_commit_txn(const char **conflict_p,
                        svn_repos_t *repos,
                        svn_revnum_t *new_rev,
                        svn_fs_txn_t *txn,
                        apr_pool_t *pool)
{
    svn_error_t *err, *err2;
    const char *txn_name;
    apr_hash_t *props;
    apr_pool_t *iterpool;
    apr_hash_index_t *hi;
    apr_hash_t *hooks_env;

    *new_rev = SVN_INVALID_REVNUM;

    /* Parse the hooks-env file (if any). */
    SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
                                       pool, pool));

    /* Run pre-commit hooks. */
    SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
    SVN_ERR(svn_repos__hooks_pre_commit(repos, hooks_env, txn_name, pool));

    /* Remove any ephemeral transaction properties. */
    SVN_ERR(svn_fs_txn_proplist(&props, txn, pool));
    iterpool = svn_pool_create(pool);
    for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
    {
        const void *key;
        apr_hash_this(hi, &key, NULL, NULL);

        svn_pool_clear(iterpool);

        if (strncmp(key, SVN_PROP_TXN_PREFIX,
                    (sizeof(SVN_PROP_TXN_PREFIX) - 1)) == 0)
        {
            SVN_ERR(svn_fs_change_txn_prop(txn, key, NULL, iterpool));
        }
    }
    svn_pool_destroy(iterpool);

    /* Commit. */
    err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
    if (! SVN_IS_VALID_REVNUM(*new_rev))
        return err;

    /* Run post-commit hooks. */
    if ((err2 = svn_repos__hooks_post_commit(repos, hooks_env,
                *new_rev, txn_name, pool)))
    {
        err2 = svn_error_create
               (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err2,
                _("Commit succeeded, but post-commit hook failed"));
    }

    return svn_error_compose_create(err, err2);
}
Esempio n. 14
0
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
            apr_pool_t *scratch_pool)
{
  struct ev2_baton *eb = baton;
  svn_revnum_t revision;
  svn_error_t *post_commit_err;
  const char *conflict_path;
  svn_error_t *err;
  const char *post_commit_errstr;
  apr_hash_t *hooks_env;

  /* Parse the hooks-env file (if any). */
  SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, eb->repos->hooks_env_path,
                                     scratch_pool, scratch_pool));

  /* The transaction has been fully edited. Let the pre-commit hook
     have a look at the thing.  */
  SVN_ERR(svn_repos__hooks_pre_commit(eb->repos, hooks_env,
                                      eb->txn_name, scratch_pool));

  /* Hook is done. Let's do the actual commit.  */
  SVN_ERR(svn_fs__editor_commit(&revision, &post_commit_err, &conflict_path,
                                eb->inner, scratch_pool, scratch_pool));

  /* Did a conflict occur during the commit process?  */
  if (conflict_path != NULL)
    return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
                             _("Conflict at '%s'"), conflict_path);

  /* Since did not receive an error during the commit process, and no
     conflict was specified... we committed a revision. Run the hooks.
     Other errors may have occurred within the FS (specified by the
     POST_COMMIT_ERR localvar), but we need to run the hooks.  */
  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
  err = svn_repos__hooks_post_commit(eb->repos, hooks_env, revision,
                                     eb->txn_name, scratch_pool);
  if (err)
    err = svn_error_create(SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
                           _("Commit succeeded, but post-commit hook failed"));

  /* Combine the FS errors with the hook errors, and stringify.  */
  err = svn_error_compose_create(post_commit_err, err);
  if (err)
    {
      post_commit_errstr = svn_repos__post_commit_error_str(err, scratch_pool);
      svn_error_clear(err);
    }
  else
    {
      post_commit_errstr = NULL;
    }

  return svn_error_trace(invoke_commit_cb(eb->commit_cb, eb->commit_baton,
                                          eb->repos->fs, revision,
                                          post_commit_errstr,
                                          scratch_pool));
}
Esempio n. 15
0
svn_error_t *
svn_client__switch_internal(svn_revnum_t *result_rev,
                            const char *path,
                            const char *switch_url,
                            const svn_opt_revision_t *peg_revision,
                            const svn_opt_revision_t *revision,
                            svn_depth_t depth,
                            svn_boolean_t depth_is_sticky,
                            svn_boolean_t ignore_externals,
                            svn_boolean_t allow_unver_obstructions,
                            svn_boolean_t ignore_ancestry,
                            svn_boolean_t *timestamp_sleep,
                            svn_client_ctx_t *ctx,
                            apr_pool_t *pool)
{
  const char *local_abspath, *anchor_abspath;
  svn_boolean_t acquired_lock;
  svn_error_t *err, *err1, *err2;
  apr_hash_t *conflicted_paths
    = ctx->conflict_func2 ? apr_hash_make(pool) : NULL;

  SVN_ERR_ASSERT(path);

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  /* Rely on svn_wc__acquire_write_lock setting ANCHOR_ABSPATH even
     when it returns SVN_ERR_WC_LOCKED */
  err = svn_wc__acquire_write_lock(&anchor_abspath,
                                   ctx->wc_ctx, local_abspath, TRUE,
                                   pool, pool);
  if (err && err->apr_err != SVN_ERR_WC_LOCKED)
    return svn_error_trace(err);

  acquired_lock = (err == SVN_NO_ERROR);
  svn_error_clear(err);

  err1 = switch_internal(result_rev, conflicted_paths,
                         local_abspath, anchor_abspath,
                         switch_url, peg_revision, revision,
                         depth, depth_is_sticky,
                         ignore_externals,
                         allow_unver_obstructions, ignore_ancestry,
                         timestamp_sleep, ctx, pool);

  /* Give the conflict resolver callback the opportunity to
   * resolve any conflicts that were raised. */
  if (! err1 && ctx->conflict_func2)
    {
      err1 = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool);
    }

  if (acquired_lock)
    err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool);
  else
    err2 = SVN_NO_ERROR;

  return svn_error_compose_create(err1, err2);
}
Esempio n. 16
0
svn_error_t *
svn_ra_serf__get_file_revs(svn_ra_session_t *ra_session,
                           const char *path,
                           svn_revnum_t start,
                           svn_revnum_t end,
                           svn_boolean_t include_merged_revisions,
                           svn_file_rev_handler_t rev_handler,
                           void *rev_handler_baton,
                           apr_pool_t *pool)
{
  blame_context_t *blame_ctx;
  svn_ra_serf__session_t *session = ra_session->priv;
  svn_ra_serf__handler_t *handler;
  svn_ra_serf__xml_context_t *xmlctx;
  const char *req_url;
  svn_error_t *err;

  blame_ctx = apr_pcalloc(pool, sizeof(*blame_ctx));
  blame_ctx->pool = pool;
  blame_ctx->path = path;
  blame_ctx->file_rev = rev_handler;
  blame_ctx->file_rev_baton = rev_handler_baton;
  blame_ctx->start = start;
  blame_ctx->end = end;
  blame_ctx->include_merged_revisions = include_merged_revisions;

  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
                                      session, NULL /* conn */,
                                      NULL /* url */, end,
                                      pool, pool));

  xmlctx = svn_ra_serf__xml_context_create(blame_ttable,
                                           blame_opened,
                                           blame_closed,
                                           blame_cdata,
                                           blame_ctx,
                                           pool);
  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);

  handler->method = "REPORT";
  handler->path = req_url;
  handler->body_type = "text/xml";
  handler->body_delegate = create_file_revs_body;
  handler->body_delegate_baton = blame_ctx;
  handler->conn = session->conns[0];
  handler->session = session;

  err = svn_ra_serf__context_run_one(handler, pool);

  err = svn_error_compose_create(
            svn_ra_serf__error_on_status(handler->sline,
                                         handler->path,
                                         handler->location),
            err);

  return svn_error_trace(err);
}
Esempio n. 17
0
/* Utility that releases the lock previously acquired via lock().  If the
 * unlock succeeds and OUTER_ERR is not NULL, OUTER_ERR will be returned.
 * Otherwise, return the result of the unlock operation.
 */
static svn_error_t *
unlock(struct mutex_t *mutex, svn_error_t * outer_err)
{
  svn_error_t *unlock_err
      = svn_io_unlock_open_file(mutex->lock_file, mutex->pool);
  return svn_mutex__unlock(thread_mutex,
                           svn_error_compose_create(outer_err,
                                                    unlock_err));
}
Esempio n. 18
0
svn_error_t *
svn_error_purge_tracing(svn_error_t *err)
{
#ifdef SVN_ERR__TRACING
  svn_error_t *new_err = NULL, *new_err_leaf = NULL;

  if (! err)
    return SVN_NO_ERROR;

  do
    {
      svn_error_t *tmp_err;

      /* Skip over any trace-only links. */
      while (err && svn_error__is_tracing_link(err))
        err = err->child;

      /* The link must be a real link in the error chain, otherwise an
         error chain with trace only links would map into SVN_NO_ERROR. */
      if (! err)
        return svn_error_create(
                 SVN_ERR_ASSERTION_ONLY_TRACING_LINKS,
                 svn_error_compose_create(
                   svn_error__malfunction(TRUE, __FILE__, __LINE__,
                                          NULL /* ### say something? */),
                   err),
                 NULL);

      /* Copy the current error except for its child error pointer
         into the new error.  Share any message and source filename
         strings from the error. */
      tmp_err = apr_palloc(err->pool, sizeof(*tmp_err));
      *tmp_err = *err;
      tmp_err->child = NULL;

      /* Add a new link to the new chain (creating the chain if necessary). */
      if (! new_err)
        {
          new_err = tmp_err;
          new_err_leaf = tmp_err;
        }
      else
        {
          new_err_leaf->child = tmp_err;
          new_err_leaf = tmp_err;
        }

      /* Advance to the next link in the original chain. */
      err = err->child;
    } while (err);

  return new_err;
#else  /* SVN_ERR__TRACING */
  return err;
#endif /* SVN_ERR__TRACING */
}
Esempio n. 19
0
svn_error_t *
svn_sqlite__with_lock(svn_sqlite__db_t *db,
                      svn_sqlite__transaction_callback_t cb_func,
                      void *cb_baton,
                      apr_pool_t *scratch_pool)
{
  svn_error_t *err;
  int savepoint = db->savepoint_nr++;
  /* This buffer is plenty big to hold the SAVEPOINT and RELEASE commands. */
  char buf[32];

  snprintf(buf, sizeof(buf), "SAVEPOINT s%u", savepoint);
  SVN_ERR(exec_sql(db, buf));
  err = cb_func(cb_baton, db, scratch_pool);

  if (err)
    {
      svn_error_t *err2;

      snprintf(buf, sizeof(buf), "ROLLBACK TO s%u", savepoint);
      err2 = exec_sql(db, buf);

      if (err2 && err2->apr_err == SVN_ERR_SQLITE_BUSY)
        {
          /* Ok, we have a major problem. Some statement is still open, which
             makes it impossible to release this savepoint.

             ### See huge comment in svn_sqlite__with_transaction for
                 further details */

          err2 = reset_all_statements(db, err2);
          err2 = svn_error_compose_create(exec_sql(db, buf), err2);
        }

      snprintf(buf, sizeof(buf), "RELEASE   s%u", savepoint);
      err2 = svn_error_compose_create(exec_sql(db, buf), err2);

      return svn_error_trace(svn_error_compose_create(err, err2));
    }

  snprintf(buf, sizeof(buf), "RELEASE   s%u", savepoint);
  return svn_error_trace(exec_sql(db, buf));
}
Esempio n. 20
0
svn_error_t *
svn_ra_serf__get_locations(svn_ra_session_t *ra_session,
                           apr_hash_t **locations,
                           const char *path,
                           svn_revnum_t peg_revision,
                           const apr_array_header_t *location_revisions,
                           apr_pool_t *pool)
{
  loc_context_t *loc_ctx;
  svn_ra_serf__session_t *session = ra_session->priv;
  svn_ra_serf__handler_t *handler;
  svn_ra_serf__xml_context_t *xmlctx;
  const char *req_url;
  svn_error_t *err;

  loc_ctx = apr_pcalloc(pool, sizeof(*loc_ctx));
  loc_ctx->pool = pool;
  loc_ctx->path = path;
  loc_ctx->peg_revision = peg_revision;
  loc_ctx->location_revisions = location_revisions;
  loc_ctx->paths = apr_hash_make(loc_ctx->pool);

  *locations = loc_ctx->paths;

  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
                                      session, NULL /* conn */,
                                      NULL /* url */, peg_revision,
                                      pool, pool));

  xmlctx = svn_ra_serf__xml_context_create(getloc_ttable,
                                           NULL, getloc_closed, NULL,
                                           loc_ctx,
                                           pool);
  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);

  handler->method = "REPORT";
  handler->path = req_url;
  handler->body_delegate = create_get_locations_body;
  handler->body_delegate_baton = loc_ctx;
  handler->body_type = "text/xml";
  handler->conn = session->conns[0];
  handler->session = session;

  err = svn_ra_serf__context_run_one(handler, pool);

  SVN_ERR(svn_error_compose_create(
              svn_ra_serf__error_on_status(handler->sline.code,
                                           req_url,
                                           handler->location),
              err));

  return SVN_NO_ERROR;
}
Esempio n. 21
0
static svn_error_t *
reset_all_statements(svn_sqlite__db_t *db,
                     svn_error_t *error_to_wrap)
{
  int i;
  svn_error_t *err;

  /* ### Should we reorder the errors in this specific case
     ### to avoid returning the normal error as top level error? */

  err = svn_error_compose_create(error_to_wrap,
                   svn_error_create(SVN_ERR_SQLITE_RESETTING_FOR_ROLLBACK,
                                    NULL, NULL));

  for (i = 0; i < db->nbr_statements; i++)
    if (db->prepared_stmts[i] && db->prepared_stmts[i]->needs_reset)
      err = svn_error_compose_create(err,
                                svn_sqlite__reset(db->prepared_stmts[i]));

  return err;
}
Esempio n. 22
0
svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
                              svn_cancel_func_t cancel_func,
                              void *cancel_baton,
                              apr_pool_t *scratch_pool)
{
  char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
  svn_error_t *err;
  svn_error_t *err2;

  /* Read and write chunks until we get a short read, indicating the
     end of the stream.  (We can't get a short write without an
     associated error.) */
  while (1)
    {
      apr_size_t len = SVN__STREAM_CHUNK_SIZE;

      if (cancel_func)
        {
          err = cancel_func(cancel_baton);
          if (err)
             break;
        }

      err = svn_stream_read(from, buf, &len);
      if (err)
         break;

      if (len > 0)
        err = svn_stream_write(to, buf, &len);

      if (err || (len != SVN__STREAM_CHUNK_SIZE))
          break;
    }

  err2 = svn_error_compose_create(svn_stream_close(from),
                                  svn_stream_close(to));

  return svn_error_compose_create(err, err2);
}
Esempio n. 23
0
svn_error_t *
svn_fs_fs__with_rep_cache_lock(svn_fs_t *fs,
                               svn_error_t *(*body)(void *,
                                                    apr_pool_t *),
                               void *baton,
                               apr_pool_t *pool)
{
  svn_error_t *err;

  SVN_ERR(lock_rep_cache(fs, pool));
  err = body(baton, pool);
  return svn_error_compose_create(err, unlock_rep_cache(fs, pool));
}
Esempio n. 24
0
/* Transaction implementation of svn_wc__db_pristine_transfer().
   We have a lock on DST_WCROOT.
 */
static svn_error_t *
pristine_transfer_txn(svn_wc__db_wcroot_t *src_wcroot,
                       svn_wc__db_wcroot_t *dst_wcroot,
                       const char *src_relpath,
                       svn_cancel_func_t cancel_func,
                       void *cancel_baton,
                       apr_pool_t *scratch_pool)
{
  svn_sqlite__stmt_t *stmt;
  svn_boolean_t got_row;
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);

  SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
                                    STMT_SELECT_COPY_PRISTINES));
  SVN_ERR(svn_sqlite__bindf(stmt, "is", src_wcroot->wc_id, src_relpath));

  /* This obtains an sqlite read lock on src_wcroot */
  SVN_ERR(svn_sqlite__step(&got_row, stmt));

  while (got_row)
    {
      const svn_checksum_t *checksum;
      const svn_checksum_t *md5_checksum;
      apr_int64_t size;
      svn_error_t *err;

      svn_pool_clear(iterpool);

      SVN_ERR(svn_sqlite__column_checksum(&checksum, stmt, 0, iterpool));
      SVN_ERR(svn_sqlite__column_checksum(&md5_checksum, stmt, 1, iterpool));
      size = svn_sqlite__column_int64(stmt, 2);

      err = maybe_transfer_one_pristine(src_wcroot, dst_wcroot,
                                        checksum, md5_checksum, size,
                                        cancel_func, cancel_baton,
                                        iterpool);

      if (err)
        return svn_error_trace(svn_error_compose_create(
                                    err,
                                    svn_sqlite__reset(stmt)));

      SVN_ERR(svn_sqlite__step(&got_row, stmt));
    }
  SVN_ERR(svn_sqlite__reset(stmt));

  svn_pool_destroy(iterpool);

  return SVN_NO_ERROR;
}
Esempio n. 25
0
svn_error_t *
svn_stream_contents_same2(svn_boolean_t *same,
                          svn_stream_t *stream1,
                          svn_stream_t *stream2,
                          apr_pool_t *pool)
{
  char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
  char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
  apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE;
  apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE;
  svn_error_t *err = NULL;

  *same = TRUE;  /* assume TRUE, until disproved below */
  while (bytes_read1 == SVN__STREAM_CHUNK_SIZE
         && bytes_read2 == SVN__STREAM_CHUNK_SIZE)
    {
      err = svn_stream_read(stream1, buf1, &bytes_read1);
      if (err)
        break;
      err = svn_stream_read(stream2, buf2, &bytes_read2);
      if (err)
        break;

      if ((bytes_read1 != bytes_read2)
          || (memcmp(buf1, buf2, bytes_read1)))
        {
          *same = FALSE;
          break;
        }
    }

  return svn_error_compose_create(err,
                                  svn_error_compose_create(
                                    svn_stream_close(stream1),
                                    svn_stream_close(stream2)));
}
Esempio n. 26
0
svn_error_t *
svn_client__switch_internal(svn_revnum_t *result_rev,
                            const char *path,
                            const char *switch_url,
                            const svn_opt_revision_t *peg_revision,
                            const svn_opt_revision_t *revision,
                            svn_depth_t depth,
                            svn_boolean_t depth_is_sticky,
                            svn_boolean_t ignore_externals,
                            svn_boolean_t allow_unver_obstructions,
                            svn_boolean_t ignore_ancestry,
                            svn_boolean_t *timestamp_sleep,
                            svn_client_ctx_t *ctx,
                            apr_pool_t *pool)
{
  const char *local_abspath, *anchor_abspath;
  svn_boolean_t acquired_lock;
  svn_error_t *err, *err1, *err2;

  SVN_ERR_ASSERT(path);

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  /* Rely on svn_wc__acquire_write_lock setting ANCHOR_ABSPATH even
     when it returns SVN_ERR_WC_LOCKED */
  err = svn_wc__acquire_write_lock(&anchor_abspath,
                                   ctx->wc_ctx, local_abspath, TRUE,
                                   pool, pool);
  if (err && err->apr_err != SVN_ERR_WC_LOCKED)
    return svn_error_trace(err);

  acquired_lock = (err == SVN_NO_ERROR);
  svn_error_clear(err);

  err1 = switch_internal(result_rev, local_abspath, anchor_abspath,
                         switch_url, peg_revision, revision,
                         depth, depth_is_sticky,
                         ignore_externals,
                         allow_unver_obstructions, ignore_ancestry,
                         timestamp_sleep, ctx, pool);

  if (acquired_lock)
    err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool);
  else
    err2 = SVN_NO_ERROR;

  return svn_error_compose_create(err1, err2);
}
Esempio n. 27
0
svn_error_t *
svn_sqlite__step(svn_boolean_t *got_row, svn_sqlite__stmt_t *stmt)
{
  int sqlite_result = sqlite3_step(stmt->s3stmt);

  if (sqlite_result != SQLITE_DONE && sqlite_result != SQLITE_ROW)
    {
      svn_error_t *err1, *err2;

      err1 = svn_error_create(SQLITE_ERROR_CODE(sqlite_result), NULL,
                              sqlite3_errmsg(stmt->db->db3));
      err2 = svn_sqlite__reset(stmt);
      return svn_error_compose_create(err1, err2);
    }

  *got_row = (sqlite_result == SQLITE_ROW);

  return SVN_NO_ERROR;
}
Esempio n. 28
0
int
main(int argc, const char *argv[])
{
  apr_pool_t *pool;
  int exit_code = EXIT_SUCCESS;
  svn_error_t *err;

  /* Initialize the app. */
  if (svn_cmdline_init("svnserve", stderr) != EXIT_SUCCESS)
    return EXIT_FAILURE;

  /* Create our top-level pool. */
  pool = apr_allocator_owner_get(svn_pool_create_allocator(TRUE));

  err = sub_main(&exit_code, argc, argv, pool);

  /* Flush stdout and report if it fails. It would be flushed on exit anyway
     but this makes sure that output is not silently lost if it fails. */
  err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));

  if (err)
    {
      exit_code = EXIT_FAILURE;
      svn_cmdline_handle_exit_error(err, NULL, "svnserve: ");
    }

#if APR_HAS_THREADS
  /* Explicitly wait for all threads to exit.  As we found out with similar
     code in our C test framework, the memory pool cleanup below cannot be
     trusted to do the right thing. */
  if (threads)
    apr_thread_pool_destroy(threads);
#endif

  /* this will also close the server's socket */
  svn_pool_destroy(pool);
  return exit_code;
}
Esempio n. 29
0
svn_error_t *
svn_client__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)
{
  const char *old_session_url;
  svn_error_t *err;

  if (!SVN_IS_VALID_REVNUM(revision))
    return SVN_NO_ERROR;

  if (ra_session)
    SVN_ERR(svn_ra_get_session_url(ra_session, &old_session_url, scratch_pool));

  /* We just wrap a simple helper function, as it is to easy to leave the ra
     session rooted at some wrong path without a wrapper like this.

     During development we had problems where some now deleted switched path
     made the update try to update to that url instead of the intended url
   */

  err = get_inheritable_props(wcroot_iprops, local_abspath, revision, depth,
                              ra_session, ctx, result_pool, scratch_pool);

  if (ra_session)
    {
      err = svn_error_compose_create(
                err,
                svn_ra_reparent(ra_session, old_session_url, scratch_pool));
    }
  return svn_error_trace(err);
}
Esempio n. 30
0
svn_error_t *svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn,
                                      apr_pool_t *pool,
                                      const svn_delta_editor_t *editor,
                                      void *edit_baton,
                                      svn_boolean_t *aborted,
                                      svn_boolean_t for_replay)
{
  ra_svn_driver_state_t state;
  apr_pool_t *subpool = svn_pool_create(pool);
  const char *cmd;
  int i;
  svn_error_t *err, *write_err;
  apr_array_header_t *params;

  state.editor = editor;
  state.edit_baton = edit_baton;
  state.tokens = apr_hash_make(pool);
  state.aborted = aborted;
  state.done = FALSE;
  state.pool = pool;
  state.file_pool = svn_pool_create(pool);
  state.file_refs = 0;
  state.for_replay = for_replay;

  while (!state.done)
    {
      svn_pool_clear(subpool);
      if (editor)
        {
          SVN_ERR(svn_ra_svn__read_tuple(conn, subpool, "wl", &cmd, &params));
          for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
              if (strcmp(cmd, ra_svn_edit_cmds[i].cmd) == 0)
                break;

          if (ra_svn_edit_cmds[i].cmd)
            err = (*ra_svn_edit_cmds[i].handler)(conn, subpool, params, &state);
          else if (strcmp(cmd, "failure") == 0)
            {
              /* While not really an editor command this can occur when
                reporter->finish_report() fails before the first editor
                command */
              if (aborted)
                *aborted = TRUE;
              err = svn_ra_svn__handle_failure_status(params, pool);
              return svn_error_compose_create(
                                err,
                                editor->abort_edit(edit_baton, subpool));
            }
          else
            {
              err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
                                      _("Unknown editor command '%s'"), cmd);
              err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
            }
        }
      else
        {
          const char* command = NULL;
          SVN_ERR(svn_ra_svn__read_command_only(conn, subpool, &command));
          if (strcmp(command, "close-edit") == 0)
            {
              state.done = TRUE;
              if (aborted)
                *aborted = FALSE;
              err = svn_ra_svn__write_cmd_response(conn, pool, "");
            }
          else
            err = NULL;
        }

      if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
        {
          if (aborted)
            *aborted = TRUE;
          if (!state.done)
            {
              /* Abort the edit and use non-blocking I/O to write the error. */
              if (editor)
                svn_error_clear(editor->abort_edit(edit_baton, subpool));
              svn_ra_svn__set_block_handler(conn, blocked_write, &state);
            }
          write_err = svn_ra_svn__write_cmd_failure(
                          conn, subpool,
                          svn_ra_svn__locate_real_error_child(err));
          if (!write_err)
            write_err = svn_ra_svn__flush(conn, subpool);
          svn_ra_svn__set_block_handler(conn, NULL, NULL);
          svn_error_clear(err);
          SVN_ERR(write_err);
          break;
        }
      SVN_ERR(err);
    }

  /* Read and discard editing commands until the edit is complete.
     Hopefully, the other side will call another editor command, run
     check_for_error, notice the error, write "abort-edit" at us, and
     throw the error up a few levels on its side (possibly even
     tossing it right back at us, which is why we can return
     SVN_NO_ERROR below).

     However, if the other side is way ahead of us, it might
     completely finish the edit (or sequence of edit/revprops, for
     "replay-range") before we send over our "failure".  So we should
     also stop if we see "success".  (Then the other side will try to
     interpret our "failure" as a command, which will itself fail...
     The net effect is that whatever error we wrote to the other side
     will be replaced with SVN_ERR_RA_SVN_UNKNOWN_CMD.)
   */
  while (!state.done)
    {
      svn_pool_clear(subpool);
      err = svn_ra_svn__read_tuple(conn, subpool, "wl", &cmd, &params);
      if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
        {
          /* Other side disconnected; that's no error. */
          svn_error_clear(err);
          svn_pool_destroy(subpool);
          return SVN_NO_ERROR;
        }
      svn_error_clear(err);
      if (strcmp(cmd, "abort-edit") == 0
          || strcmp(cmd, "success") == 0)
        state.done = TRUE;
    }

  svn_pool_destroy(subpool);
  return SVN_NO_ERROR;
}