svn_error_t * svn_client_create_context2(svn_client_ctx_t **ctx, apr_hash_t *cfg_hash, apr_pool_t *pool) { svn_config_t *cfg_config; *ctx = apr_pcalloc(pool, sizeof(svn_client_ctx_t)); (*ctx)->notify_func2 = call_notify_func; (*ctx)->notify_baton2 = *ctx; (*ctx)->conflict_func2 = call_conflict_func; (*ctx)->conflict_baton2 = *ctx; (*ctx)->config = cfg_hash; if (cfg_hash) cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG); else cfg_config = NULL; SVN_ERR(svn_wc_context_create(&(*ctx)->wc_ctx, cfg_config, pool, pool)); return SVN_NO_ERROR; }
static svn_error_t * obtain_lock(const char *path, svn_boolean_t recursive, apr_pool_t *scratch_pool) { const char *local_abspath; svn_wc_context_t *wc_ctx; SVN_ERR(svn_path_cstring_to_utf8(&path, path, scratch_pool)); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, scratch_pool)); if (recursive) { /* The WC-NG way */ SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath, FALSE, scratch_pool, scratch_pool)); } else { SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, local_abspath, 0, FALSE, scratch_pool)); } SVN_ERR(svn_cmdline_printf(scratch_pool, "Lock on '%s' obtained, and we " "are not going to release it.\n", svn_dirent_local_style(local_abspath, scratch_pool))); return SVN_NO_ERROR; }
/* Print all not-hidden subdirectories in the working copy, starting by path */ static svn_error_t * directory_dump(const char *path, apr_pool_t *scratch_pool) { struct directory_walk_baton bt; svn_error_t *err; SVN_ERR(svn_wc_context_create(&bt.wc_ctx, NULL, scratch_pool, scratch_pool)); SVN_ERR(svn_dirent_get_absolute(&bt.root_abspath, path, scratch_pool)); bt.prefix_path = path; err = svn_wc__internal_walk_children(bt.wc_ctx->db, bt.root_abspath, FALSE, NULL, print_dir, &bt, svn_depth_infinity, NULL, NULL, scratch_pool); if (err) { const char *dir_abspath; if (err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED) return err; svn_error_clear(err); SVN_ERR(svn_dirent_get_absolute(&dir_abspath, path, scratch_pool)); SVN_ERR(directory_dump_old(&bt, dir_abspath, scratch_pool)); } return svn_error_trace(svn_wc_context_destroy(bt.wc_ctx)); }
svn_error_t * svn_test__sandbox_create(svn_test__sandbox_t *sandbox, const char *test_name, const svn_test_opts_t *opts, apr_pool_t *pool) { sandbox->pool = pool; SVN_ERR(create_repos_and_wc(&sandbox->repos_url, &sandbox->wc_abspath, test_name, opts, pool)); SVN_ERR(svn_wc_context_create(&sandbox->wc_ctx, NULL, pool, pool)); return SVN_NO_ERROR; }
static svn_error_t * raise_tree_conflict(int argc, const char **argv, apr_pool_t *pool) { int i = 0; svn_wc_conflict_version_t *left, *right; svn_wc_conflict_description2_t *c; svn_wc_context_t *wc_ctx; /* Conflict description parameters */ const char *wc_path, *wc_abspath; const char *repos_url1, *repos_url2, *path_in_repos1, *path_in_repos2; int operation, action, reason; long peg_rev1, peg_rev2; int kind, kind1, kind2; if (argc != 13) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, "Wrong number of arguments"); /* Read the parameters */ wc_path = svn_dirent_internal_style(argv[i++], pool); SVN_ERR(read_enum_field(&kind, node_kind_map, argv[i++], pool)); SVN_ERR(read_enum_field(&operation, operation_map, argv[i++], pool)); SVN_ERR(read_enum_field(&action, action_map, argv[i++], pool)); SVN_ERR(read_enum_field(&reason, reason_map, argv[i++], pool)); repos_url1 = argv[i++]; path_in_repos1 = argv[i++]; peg_rev1 = atol(argv[i++]); SVN_ERR(read_enum_field(&kind1, node_kind_map, argv[i++], pool)); repos_url2 = argv[i++]; path_in_repos2 = argv[i++]; peg_rev2 = atol(argv[i++]); SVN_ERR(read_enum_field(&kind2, node_kind_map, argv[i++], pool)); /* Allocate and fill in the description data structures */ SVN_ERR(svn_dirent_get_absolute(&wc_abspath, wc_path, pool)); left = svn_wc_conflict_version_create2(repos_url1, NULL, path_in_repos1, peg_rev1, kind1, pool); right = svn_wc_conflict_version_create2(repos_url2, NULL, path_in_repos2, peg_rev2, kind2, pool); c = svn_wc_conflict_description_create_tree2(wc_abspath, kind, operation, left, right, pool); c->action = (svn_wc_conflict_action_t)action; c->reason = (svn_wc_conflict_reason_t)reason; /* Raise the conflict */ SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool)); SVN_ERR(svn_wc__add_tree_conflict(wc_ctx, c, pool)); return SVN_NO_ERROR; }
svn_client_ctx_t * ClientContext::getContext(CommitMessage *message, SVN::Pool &in_pool) { apr_pool_t *pool = in_pool.getPool(); svn_client_ctx_t *ctx = m_context; /* Make a temporary copy of ctx to restore at pool cleanup to avoid leaving references to dangling pointers. Note that this allows creating a stack of context changes if the function is invoked multiple times with different pools. */ clearctx_baton_t *bt = reinterpret_cast<clearctx_baton_t *>(apr_pcalloc(pool, sizeof(*bt))); bt->ctx = ctx; bt->backup = reinterpret_cast<svn_client_ctx_t*>(apr_pmemdup(pool, ctx, sizeof(*ctx))); apr_pool_cleanup_register(in_pool.getPool(), bt, clear_ctx_ptrs, clear_ctx_ptrs); if (!ctx->config) { apr_hash_t * configData = getConfigData(); ctx->config = configData; bt->backup->config = ctx->config; } ctx->auth_baton = getAuthBaton(in_pool); ctx->log_msg_baton3 = message; resetCancelRequest(); SVN_JNI_ERR(svn_wc_context_create(&ctx->wc_ctx, NULL, in_pool.getPool(), in_pool.getPool()), NULL); return ctx; }
static svn_error_t * verify_db(int argc, const char *path, apr_pool_t *pool) { const char *local_abspath; svn_wc_context_t *wc_ctx; struct verify_baton vb = { FALSE }; /* Read the parameters */ path = svn_dirent_internal_style(path, pool); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool)); SVN_ERR(svn_wc__db_verify_db_full(wc_ctx->db, local_abspath, verify_cb, &vb, pool)); if (vb.found_err) return svn_error_create(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("Found one or more potential wc.db inconsistencies")); return SVN_NO_ERROR; }
static svn_error_t * test_access_baton_like_locking(apr_pool_t *pool) { svn_wc__db_t *db; svn_wc_context_t *wc_ctx, *wc_ctx2; const char *local_abspath; const char *D, *D1, *D2, *D3, *D4; svn_boolean_t locked_here, locked; svn_error_t *err; svn_wc_adm_access_t *adm_access, *subdir_access; #undef WC_NAME #define WC_NAME "test_access_batons" SVN_ERR(create_open(&db, &local_abspath, WC_NAME, pool)); D = svn_dirent_join(local_abspath, "DD", pool); D1 = svn_dirent_join(D, "DD", pool); D2 = svn_dirent_join(D1, "DD", pool); D3 = svn_dirent_join(D2, "DD", pool); D4 = svn_dirent_join(D3, "DD", pool); SVN_ERR(svn_io_make_dir_recursively(D4, pool)); /* Use the legacy interface */ SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, local_abspath, TRUE, 0, NULL, NULL, pool)); SVN_ERR(svn_wc_add3(D, adm_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, D, pool)); SVN_ERR(svn_wc_add3(D1, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, D1, pool)); SVN_ERR(svn_wc_add3(D2, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, D2, pool)); SVN_ERR(svn_wc_add3(D3, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add3(D4, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked(&locked, D3, pool)); SVN_TEST_ASSERT(locked); SVN_ERR(svn_wc_locked(&locked, D4, pool)); SVN_TEST_ASSERT(locked); SVN_ERR(svn_wc_delete3(D4, subdir_access, NULL, NULL, NULL, NULL, FALSE, pool)); SVN_ERR(svn_wc_locked(&locked, D4, pool)); SVN_TEST_ASSERT(!locked); SVN_ERR(svn_wc_revert3(D, adm_access, svn_depth_infinity, FALSE, NULL, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked(&locked, D3, pool)); SVN_TEST_ASSERT(!locked); SVN_ERR(svn_wc_locked(&locked, local_abspath, pool)); SVN_TEST_ASSERT(locked); SVN_ERR(svn_wc_adm_close2(adm_access, pool)); SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool)); /* Obtain a lock for the root, which is extended on each level */ SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, local_abspath, 0, FALSE, pool)); SVN_ERR(svn_io_make_dir_recursively(D4, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D1, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D2, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D3, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D3, pool)); SVN_TEST_ASSERT(locked_here && locked); /* Test if the not added path is already locked */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D4, pool)); SVN_TEST_ASSERT(!locked_here && !locked); SVN_ERR(svn_wc_add4(wc_ctx, D4, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D4, pool)); SVN_TEST_ASSERT(locked_here && locked); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, local_abspath, pool)); /* Should be unlocked */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, local_abspath, pool)); SVN_TEST_ASSERT(!locked_here && !locked); /* Lock shouldn't be released */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D, pool)); SVN_TEST_ASSERT(locked_here && locked); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D1, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D2, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D3, pool)); /* Try reobtaining lock on D3; should succeed */ SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, D3, 0, FALSE, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D4, pool)); /* D3 should still be locked; try stealing in a different context */ SVN_ERR(svn_wc_context_create(&wc_ctx2, NULL, pool, pool)); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx2, D3, pool)); SVN_TEST_ASSERT(!locked_here && locked); err = svn_wc__db_wclock_obtain(wc_ctx2->db, D3, 0, FALSE, pool); if (err && err->apr_err != SVN_ERR_WC_LOCKED) return svn_error_trace(err); svn_error_clear(err); SVN_TEST_ASSERT(err != NULL); /* Can't lock, as it is still locked */ err = svn_wc__db_wclock_release(wc_ctx2->db, D4, pool); if (err && err->apr_err != SVN_ERR_WC_NOT_LOCKED) return svn_error_trace(err); svn_error_clear(err); SVN_TEST_ASSERT(err != NULL); /* Can't unlock, as it is not ours */ /* Now steal the lock */ SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx2->db, D3, 0, TRUE, pool)); /* We should own the lock now */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx2, D3, pool)); SVN_TEST_ASSERT(locked_here && locked); err = svn_wc__db_wclock_release(wc_ctx2->db, D4, pool); if (err && err->apr_err != SVN_ERR_WC_NOT_LOCKED) return svn_error_trace(err); svn_error_clear(err); SVN_TEST_ASSERT(err != NULL); /* Can't unlock a not locked path */ /* Now create a separate working copy from the same repository directly below this WC and test if our code really sees it as a separate wc, for locking and normal operation */ { const char *url, *repos_root_url, *repos_uuid; const char *subdir = svn_dirent_join(local_abspath, "sub-wc", pool); svn_boolean_t is_root; SVN_ERR(svn_wc__node_get_url(&url, wc_ctx, local_abspath, pool, pool)); SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, &repos_uuid, wc_ctx, local_abspath, pool, pool)); SVN_ERR(svn_io_make_dir_recursively(subdir, pool)); SVN_ERR(svn_wc_ensure_adm3(subdir, repos_uuid, svn_path_url_add_component2(url, "sub-wc", pool), repos_root_url, 0, svn_depth_infinity, pool)); SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL, wc_ctx->db, subdir, pool)); SVN_TEST_ASSERT(is_root); SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL, wc_ctx2->db, subdir, pool)); /* This test was added to show a regression where the next check failed, but the check above this succeeded */ SVN_TEST_ASSERT(is_root); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx2, subdir, pool)); SVN_TEST_ASSERT(!locked_here && !locked); } return SVN_NO_ERROR; }
svn_client_ctx_t * ClientContext::getContext(CommitMessage *message, SVN::Pool &in_pool) { apr_pool_t *pool = in_pool.getPool(); svn_auth_baton_t *ab; svn_client_ctx_t *ctx = m_context; /* Make a temporary copy of ctx to restore at pool cleanup to avoid leaving references to dangling pointers. Note that this allows creating a stack of context changes if the function is invoked multiple times with different pools. */ clearctx_baton_t *bt = (clearctx_baton_t *)apr_pcalloc(pool, sizeof(*bt)); bt->ctx = ctx; bt->backup = (svn_client_ctx_t*)apr_pmemdup(pool, ctx, sizeof(*ctx)); apr_pool_cleanup_register(in_pool.getPool(), bt, clear_ctx_ptrs, clear_ctx_ptrs); if (!ctx->config) { const char *configDir = m_configDir.c_str(); if (m_configDir.empty()) configDir = NULL; SVN_JNI_ERR(svn_config_get_config(&(ctx->config), configDir, m_pool->getPool()), NULL); bt->backup->config = ctx->config; } svn_config_t *config = (svn_config_t *) apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING); /* The whole list of registered providers */ apr_array_header_t *providers; /* Populate the registered providers with the platform-specific providers */ SVN_JNI_ERR(svn_auth_get_platform_specific_client_providers(&providers, config, pool), NULL); /* Use the prompter (if available) to prompt for password and cert * caching. */ svn_auth_plaintext_prompt_func_t plaintext_prompt_func = NULL; void *plaintext_prompt_baton = NULL; svn_auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func; void *plaintext_passphrase_prompt_baton = NULL; if (m_prompter != NULL) { plaintext_prompt_func = Prompter::plaintext_prompt; plaintext_prompt_baton = m_prompter; plaintext_passphrase_prompt_func = Prompter::plaintext_passphrase_prompt; plaintext_passphrase_prompt_baton = m_prompter; } /* The main disk-caching auth providers, for both * 'username/password' creds and 'username' creds. */ svn_auth_provider_object_t *provider; svn_auth_get_simple_provider2(&provider, plaintext_prompt_func, plaintext_prompt_baton, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; svn_auth_get_username_provider(&provider, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; /* The server-cert, client-cert, and client-cert-password providers. */ SVN_JNI_ERR(svn_auth_get_platform_specific_provider(&provider, "windows", "ssl_server_trust", pool), NULL); if (provider) APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; svn_auth_get_ssl_server_trust_file_provider(&provider, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; svn_auth_get_ssl_client_cert_file_provider(&provider, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; svn_auth_get_ssl_client_cert_pw_file_provider2(&provider, plaintext_passphrase_prompt_func, plaintext_passphrase_prompt_baton, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; if (m_prompter != NULL) { /* Two basic prompt providers: username/password, and just username.*/ provider = m_prompter->getProviderSimple(in_pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; provider = m_prompter->getProviderUsername(in_pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; /* Three ssl prompt providers, for server-certs, client-certs, * and client-cert-passphrases. */ provider = m_prompter->getProviderServerSSLTrust(in_pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; provider = m_prompter->getProviderClientSSL(in_pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; provider = m_prompter->getProviderClientSSLPassword(in_pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; } /* Build an authentication baton to give to libsvn_client. */ svn_auth_open(&ab, providers, pool); /* Place any default --username or --password credentials into the * auth_baton's run-time parameter hash. ### Same with --no-auth-cache? */ if (!m_userName.empty()) svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_USERNAME, apr_pstrdup(in_pool.getPool(), m_userName.c_str())); if (!m_passWord.empty()) svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD, apr_pstrdup(in_pool.getPool(), m_passWord.c_str())); /* Store where to retrieve authentication data? */ if (!m_configDir.empty()) svn_auth_set_parameter(ab, SVN_AUTH_PARAM_CONFIG_DIR, apr_pstrdup(in_pool.getPool(), m_configDir.c_str())); ctx->auth_baton = ab; ctx->log_msg_baton3 = message; m_cancelOperation = false; SVN_JNI_ERR(svn_wc_context_create(&ctx->wc_ctx, NULL, in_pool.getPool(), in_pool.getPool()), NULL); return ctx; }
/* * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error, * either return an error to be displayed, or set *EXIT_CODE to non-zero and * return SVN_NO_ERROR. * * Why is this not an svn subcommand? I have this vague idea that it could * be run as part of the build process, with the output embedded in the svn * program. Obviously we don't want to have to run svn when building svn. */ static svn_error_t * sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool) { const char *wc_path, *trail_url; const char *local_abspath; svn_wc_revision_status_t *res; svn_boolean_t no_newline = FALSE, committed = FALSE; svn_error_t *err; apr_getopt_t *os; svn_wc_context_t *wc_ctx; svn_boolean_t quiet = FALSE; svn_boolean_t is_version = FALSE; const apr_getopt_option_t options[] = { {"no-newline", 'n', 0, N_("do not output the trailing newline")}, {"committed", 'c', 0, N_("last changed rather than current revisions")}, {"help", 'h', 0, N_("display this help")}, {"version", SVNVERSION_OPT_VERSION, 0, N_("show program version information")}, {"quiet", 'q', 0, N_("no progress (only errors) to stderr")}, {0, 0, 0, 0} }; /* Check library versions */ SVN_ERR(check_lib_versions()); #if defined(WIN32) || defined(__CYGWIN__) /* Set the working copy administrative directory name. */ if (getenv("SVN_ASP_DOT_NET_HACK")) { SVN_ERR(svn_wc_set_adm_dir("_svn", pool)); } #endif SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool)); os->interleave = 1; while (1) { int opt; const char *arg; apr_status_t status = apr_getopt_long(os, options, &opt, &arg); if (APR_STATUS_IS_EOF(status)) break; if (status != APR_SUCCESS) { *exit_code = EXIT_FAILURE; usage(pool); return SVN_NO_ERROR; } switch (opt) { case 'n': no_newline = TRUE; break; case 'c': committed = TRUE; break; case 'q': quiet = TRUE; break; case 'h': help(options, pool); return SVN_NO_ERROR; case SVNVERSION_OPT_VERSION: is_version = TRUE; break; default: *exit_code = EXIT_FAILURE; usage(pool); return SVN_NO_ERROR; } } if (is_version) { SVN_ERR(version(quiet, pool)); return SVN_NO_ERROR; } if (os->ind > argc || os->ind < argc - 2) { *exit_code = EXIT_FAILURE; usage(pool); return SVN_NO_ERROR; } SVN_ERR(svn_utf_cstring_to_utf8(&wc_path, (os->ind < argc) ? os->argv[os->ind] : ".", pool)); SVN_ERR(svn_opt__arg_canonicalize_path(&wc_path, wc_path, pool)); SVN_ERR(svn_dirent_get_absolute(&local_abspath, wc_path, pool)); SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool)); if (os->ind+1 < argc) SVN_ERR(svn_utf_cstring_to_utf8(&trail_url, os->argv[os->ind+1], pool)); else trail_url = NULL; err = svn_wc_revision_status2(&res, wc_ctx, local_abspath, trail_url, committed, NULL, NULL, pool, pool); if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)) { svn_node_kind_t kind; svn_boolean_t special; svn_error_clear(err); SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &special, pool)); if (special) SVN_ERR(svn_cmdline_printf(pool, _("Unversioned symlink%s"), no_newline ? "" : "\n")); else if (kind == svn_node_dir) SVN_ERR(svn_cmdline_printf(pool, _("Unversioned directory%s"), no_newline ? "" : "\n")); else if (kind == svn_node_file) SVN_ERR(svn_cmdline_printf(pool, _("Unversioned file%s"), no_newline ? "" : "\n")); else { SVN_ERR(svn_cmdline_fprintf(stderr, pool, kind == svn_node_none ? _("'%s' doesn't exist\n") : _("'%s' is of unknown type\n"), svn_dirent_local_style(local_abspath, pool))); *exit_code = EXIT_FAILURE; return SVN_NO_ERROR; } return SVN_NO_ERROR; } SVN_ERR(err); if (! SVN_IS_VALID_REVNUM(res->min_rev)) { /* Local uncommitted modifications, no revision info was found. */ SVN_ERR(svn_cmdline_printf(pool, _("Uncommitted local addition, " "copy or move%s"), no_newline ? "" : "\n")); return SVN_NO_ERROR; } /* Build compact '123[:456]M?S?' string. */ SVN_ERR(svn_cmdline_printf(pool, "%ld", res->min_rev)); if (res->min_rev != res->max_rev) SVN_ERR(svn_cmdline_printf(pool, ":%ld", res->max_rev)); if (res->modified) SVN_ERR(svn_cmdline_fputs("M", stdout, pool)); if (res->switched) SVN_ERR(svn_cmdline_fputs("S", stdout, pool)); if (res->sparse_checkout) SVN_ERR(svn_cmdline_fputs("P", stdout, pool)); if (! no_newline) SVN_ERR(svn_cmdline_fputs("\n", stdout, pool)); return SVN_NO_ERROR; }