/* An svn_client_status_func_t callback function for finding status structures which are not safely deletable. */ static svn_error_t * find_undeletables(void *baton, const char *path, const svn_client_status_t *status, apr_pool_t *pool) { /* Check for error-ful states. */ if (status->node_status == svn_wc_status_obstructed) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("'%s' is in the way of the resource " "actually under version control"), svn_dirent_local_style(path, pool)); else if (! status->versioned) return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("'%s' is not under version control"), svn_dirent_local_style(path, pool)); else if ((status->node_status != svn_wc_status_normal && status->node_status != svn_wc_status_deleted && status->node_status != svn_wc_status_missing) || (status->prop_status != svn_wc_status_none && status->prop_status != svn_wc_status_normal)) return svn_error_createf(SVN_ERR_CLIENT_MODIFIED, NULL, _("'%s' has local modifications -- commit or " "revert them first"), svn_dirent_local_style(path, pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_hotcopy2(const char *src_path, const char *dst_path, svn_boolean_t clean, svn_boolean_t incremental, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { fs_library_vtable_t *vtable; const char *src_fs_type; svn_fs_t *src_fs; svn_fs_t *dst_fs; const char *dst_fs_type; svn_node_kind_t dst_kind; if (strcmp(src_path, dst_path) == 0) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, _("Hotcopy source and destination are equal")); SVN_ERR(svn_fs_type(&src_fs_type, src_path, scratch_pool)); SVN_ERR(get_library_vtable(&vtable, src_fs_type, scratch_pool)); src_fs = fs_new(NULL, scratch_pool); dst_fs = fs_new(NULL, scratch_pool); SVN_ERR(svn_io_check_path(dst_path, &dst_kind, scratch_pool)); if (dst_kind == svn_node_file) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("'%s' already exists and is a file"), svn_dirent_local_style(dst_path, scratch_pool)); if (dst_kind == svn_node_unknown) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("'%s' already exists and has an unknown " "node kind"), svn_dirent_local_style(dst_path, scratch_pool)); if (dst_kind == svn_node_dir) { svn_node_kind_t type_file_kind; SVN_ERR(svn_io_check_path(svn_dirent_join(dst_path, FS_TYPE_FILENAME, scratch_pool), &type_file_kind, scratch_pool)); if (type_file_kind != svn_node_none) { SVN_ERR(svn_fs_type(&dst_fs_type, dst_path, scratch_pool)); if (strcmp(src_fs_type, dst_fs_type) != 0) return svn_error_createf( SVN_ERR_ILLEGAL_TARGET, NULL, _("The filesystem type of the hotcopy source " "('%s') does not match the filesystem " "type of the hotcopy destination ('%s')"), src_fs_type, dst_fs_type); } } SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean, incremental, cancel_func, cancel_baton, scratch_pool)); return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool)); }
/* Check whether LOCAL_ABSPATH is an external and raise an error if it is. A file external should not be deleted since the file external is implemented as a switched file and it would delete the file the file external is switched to, which is not the behavior the user would probably want. A directory external should not be deleted since it is the root of a different working copy. */ static svn_error_t * check_external(const char *local_abspath, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { svn_node_kind_t external_kind; const char *defining_abspath; SVN_ERR(svn_wc__read_external_info(&external_kind, &defining_abspath, NULL, NULL, NULL, ctx->wc_ctx, local_abspath, local_abspath, TRUE, scratch_pool, scratch_pool)); if (external_kind != svn_node_none) return svn_error_createf(SVN_ERR_WC_CANNOT_DELETE_FILE_EXTERNAL, NULL, _("Cannot remove the external at '%s'; " "please edit or delete the svn:externals " "property on '%s'"), svn_dirent_local_style(local_abspath, scratch_pool), svn_dirent_local_style(defining_abspath, scratch_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_wc__get_pristine_contents(svn_stream_t **contents, svn_filesize_t *size, svn_wc__db_t *db, const char *local_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_wc__db_status_t status; svn_wc__db_kind_t kind; const svn_checksum_t *sha1_checksum; if (size) *size = SVN_INVALID_FILESIZE; SVN_ERR(svn_wc__db_read_pristine_info(&status, &kind, NULL, NULL, NULL, NULL, &sha1_checksum, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); /* Sanity */ if (kind != svn_wc__db_kind_file) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("Can only get the pristine contents of files; " "'%s' is not a file"), svn_dirent_local_style(local_abspath, scratch_pool)); if (status == svn_wc__db_status_added && !sha1_checksum) { /* Simply added. The pristine base does not exist. */ *contents = NULL; return SVN_NO_ERROR; } else if (status == svn_wc__db_status_not_present) /* We know that the delete of this node has been committed. This should be the same as if called on an unknown path. */ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, _("Cannot get the pristine contents of '%s' " "because its delete is already committed"), svn_dirent_local_style(local_abspath, scratch_pool)); else if (status == svn_wc__db_status_server_excluded || status == svn_wc__db_status_excluded || status == svn_wc__db_status_incomplete) return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("Cannot get the pristine contents of '%s' " "because it has an unexpected status"), svn_dirent_local_style(local_abspath, scratch_pool)); if (sha1_checksum) SVN_ERR(svn_wc__db_pristine_read(contents, size, db, local_abspath, sha1_checksum, result_pool, scratch_pool)); else *contents = NULL; return SVN_NO_ERROR; }
svn_error_t * svn_wc__text_base_path_to_read(const char **result_abspath, svn_wc__db_t *db, const char *local_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_wc__db_status_t status; svn_wc__db_kind_t kind; const svn_checksum_t *checksum; SVN_ERR(svn_wc__db_read_pristine_info(&status, &kind, NULL, NULL, NULL, NULL, &checksum, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); /* Sanity */ if (kind != svn_wc__db_kind_file) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("Can only get the pristine contents of files; " "'%s' is not a file"), svn_dirent_local_style(local_abspath, scratch_pool)); if (status == svn_wc__db_status_not_present) /* We know that the delete of this node has been committed. This should be the same as if called on an unknown path. */ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, _("Cannot get the pristine contents of '%s' " "because its delete is already committed"), svn_dirent_local_style(local_abspath, scratch_pool)); else if (status == svn_wc__db_status_server_excluded || status == svn_wc__db_status_excluded || status == svn_wc__db_status_incomplete) return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("Cannot get the pristine contents of '%s' " "because it has an unexpected status"), svn_dirent_local_style(local_abspath, scratch_pool)); if (checksum == NULL) return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("Node '%s' has no pristine text"), svn_dirent_local_style(local_abspath, scratch_pool)); SVN_ERR(svn_wc__db_pristine_get_path(result_abspath, db, local_abspath, checksum, result_pool, scratch_pool)); return SVN_NO_ERROR; }
/* Remove/erase PATH from the working copy. This involves deleting PATH * from the physical filesystem. PATH is assumed to be an unversioned file * or directory. * * If ignore_enoent is TRUE, ignore missing targets. * * If CANCEL_FUNC is non-null, invoke it with CANCEL_BATON at various * points, return any error immediately. */ static svn_error_t * erase_unversioned_from_wc(const char *path, svn_boolean_t ignore_enoent, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { svn_error_t *err; /* Optimize the common case: try to delete the file */ err = svn_io_remove_file2(path, ignore_enoent, scratch_pool); if (err) { /* Then maybe it was a directory? */ svn_error_clear(err); err = svn_io_remove_dir2(path, ignore_enoent, cancel_func, cancel_baton, scratch_pool); if (err) { /* We're unlikely to end up here. But we need this fallback to make sure we report the right error *and* try the correct deletion at least once. */ svn_node_kind_t kind; svn_error_clear(err); SVN_ERR(svn_io_check_path(path, &kind, scratch_pool)); if (kind == svn_node_file) SVN_ERR(svn_io_remove_file2(path, ignore_enoent, scratch_pool)); else if (kind == svn_node_dir) SVN_ERR(svn_io_remove_dir2(path, ignore_enoent, cancel_func, cancel_baton, scratch_pool)); else if (kind == svn_node_none) return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, _("'%s' does not exist"), svn_dirent_local_style(path, scratch_pool)); else return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Unsupported node kind for path '%s'"), svn_dirent_local_style(path, scratch_pool)); } } return SVN_NO_ERROR; }
static svn_error_t * file_add(const char *path, void *parent_baton, const char *copyfrom_path, svn_revnum_t copyfrom_revision, apr_pool_t *result_pool, void **file_baton) { struct dir_baton_t *pb = parent_baton; struct edit_baton_t *eb = pb->eb; apr_pool_t *file_pool = svn_pool_create(pb->pool); struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb)); svn_boolean_t under_root; pb->users++; fb->pool = file_pool; fb->eb = eb; fb->pb = pb; SVN_ERR(svn_dirent_is_under_root(&under_root, &fb->local_abspath, eb->anchor_abspath, path, fb->pool)); if (! under_root) { return svn_error_createf( SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, _("Path '%s' is not in the working copy"), svn_dirent_local_style(path, fb->pool)); } *file_baton = fb; return SVN_NO_ERROR; }
svn_error_t * svn_repos__hooks_pre_unlock(svn_repos_t *repos, const char *path, const char *username, const char *token, svn_boolean_t break_lock, apr_pool_t *pool) { const char *hook = svn_repos_pre_unlock_hook(repos, pool); svn_boolean_t broken_link; if ((hook = check_hook_cmd(hook, &broken_link, pool)) && broken_link) { return hook_symlink_error(hook); } else if (hook) { const char *args[7]; args[0] = hook; args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool); args[2] = path; args[3] = username ? username : ""; args[4] = token ? token : ""; args[5] = break_lock ? "1" : "0"; args[6] = NULL; SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_UNLOCK, hook, args, repos->hooks_env, NULL, pool)); } return SVN_NO_ERROR; }
svn_error_t * svn_wc__ensure_directory(const char *path, apr_pool_t *pool) { svn_node_kind_t kind; SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_none && kind != svn_node_dir) { /* If got an error other than dir non-existence, then we can't ensure this directory's existence, so just return the error. Might happen if there's a file in the way, for example. */ return svn_error_createf(APR_ENOTDIR, NULL, _("'%s' is not a directory"), svn_dirent_local_style(path, pool)); } else if (kind == svn_node_none) { /* The dir doesn't exist, and it's our job to change that. */ SVN_ERR(svn_io_make_dir_recursively(path, pool)); } else /* No problem, the dir already existed, so just leave. */ SVN_ERR_ASSERT(kind == svn_node_dir); return SVN_NO_ERROR; }
svn_error_t * svn_opt__arg_canonicalize_path(const char **path_out, const char *path_in, apr_pool_t *pool) { const char *apr_target; char *truenamed_target; /* APR-encoded */ apr_status_t apr_err; /* canonicalize case, and change all separators to '/'. */ SVN_ERR(svn_path_cstring_from_utf8(&apr_target, path_in, pool)); apr_err = apr_filepath_merge(&truenamed_target, "", apr_target, APR_FILEPATH_TRUENAME, pool); if (!apr_err) /* We have a canonicalized APR-encoded target now. */ apr_target = truenamed_target; else if (APR_STATUS_IS_ENOENT(apr_err)) /* It's okay for the file to not exist, that just means we have to accept the case given to the client. We'll use the original APR-encoded target. */ ; else return svn_error_createf(apr_err, NULL, _("Error resolving case of '%s'"), svn_dirent_local_style(path_in, pool)); /* convert back to UTF-8. */ SVN_ERR(svn_path_cstring_to_utf8(path_out, apr_target, pool)); *path_out = svn_dirent_canonicalize(*path_out, pool); return SVN_NO_ERROR; }
svn_error_t * svn_repos__hooks_pre_revprop_change(svn_repos_t *repos, svn_revnum_t rev, const char *author, const char *name, const svn_string_t *new_value, char action, apr_pool_t *pool) { const char *hook = svn_repos_pre_revprop_change_hook(repos, pool); svn_boolean_t broken_link; if ((hook = check_hook_cmd(hook, &broken_link, pool)) && broken_link) { return hook_symlink_error(hook); } else if (hook) { const char *args[7]; apr_file_t *stdin_handle = NULL; char action_string[2]; /* Pass the new value as stdin to hook */ if (new_value) SVN_ERR(create_temp_file(&stdin_handle, new_value, pool)); else SVN_ERR(svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME, APR_READ, APR_OS_DEFAULT, pool)); action_string[0] = action; action_string[1] = '\0'; args[0] = hook; args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool); args[2] = apr_psprintf(pool, "%ld", rev); args[3] = author ? author : ""; args[4] = name; args[5] = action_string; args[6] = NULL; SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_REVPROP_CHANGE, hook, args, repos->hooks_env, stdin_handle, pool)); SVN_ERR(svn_io_file_close(stdin_handle, pool)); } else { /* If the pre- hook doesn't exist at all, then default to MASSIVE PARANOIA. Changing revision properties is a lossy operation; so unless the repository admininstrator has *deliberately* created the pre-hook, disallow all changes. */ return svn_error_create (SVN_ERR_REPOS_DISABLED_FEATURE, NULL, _("Repository has not been enabled to accept revision propchanges;\n" "ask the administrator to create a pre-revprop-change hook")); } return SVN_NO_ERROR; }
svn_error_t * svn_wc__db_drop_root(svn_wc__db_t *db, const char *local_abspath, apr_pool_t *scratch_pool) { svn_wc__db_wcroot_t *root_wcroot = svn_hash_gets(db->dir_data, local_abspath); apr_hash_index_t *hi; apr_status_t result; if (!root_wcroot) return SVN_NO_ERROR; if (strcmp(root_wcroot->abspath, local_abspath) != 0) return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL, _("'%s' is not a working copy root"), svn_dirent_local_style(local_abspath, scratch_pool)); for (hi = apr_hash_first(scratch_pool, db->dir_data); hi; hi = apr_hash_next(hi)) { svn_wc__db_wcroot_t *wcroot = apr_hash_this_val(hi); if (wcroot == root_wcroot) svn_hash_sets(db->dir_data, apr_hash_this_key(hi), NULL); } result = apr_pool_cleanup_run(db->state_pool, root_wcroot, close_wcroot); if (result != APR_SUCCESS) return svn_error_wrap_apr(result, NULL); return SVN_NO_ERROR; }
/* Return in *LINK_TARGET_ABSPATH the absolute path the symlink at * LOCAL_ABSPATH is pointing to. Perform all allocations in POOL. */ static svn_error_t * read_link_target(const char **link_target_abspath, const char *local_abspath, apr_pool_t *pool) { svn_string_t *link_target; const char *canon_link_target; SVN_ERR(svn_io_read_link(&link_target, local_abspath, pool)); if (link_target->len == 0) return svn_error_createf(SVN_ERR_WC_NOT_SYMLINK, NULL, _("The symlink at '%s' points nowhere"), svn_dirent_local_style(local_abspath, pool)); canon_link_target = svn_dirent_canonicalize(link_target->data, pool); /* Treat relative symlinks as relative to LOCAL_ABSPATH's parent. */ if (!svn_dirent_is_absolute(canon_link_target)) canon_link_target = svn_dirent_join(svn_dirent_dirname(local_abspath, pool), canon_link_target, pool); /* Collapse any .. in the symlink part of the path. */ if (svn_path_is_backpath_present(canon_link_target)) SVN_ERR(svn_dirent_get_absolute(link_target_abspath, canon_link_target, pool)); else *link_target_abspath = canon_link_target; return SVN_NO_ERROR; }
svn_error_t * svn_cl__cleanup_log_msg(void *log_msg_baton, svn_error_t *commit_err, apr_pool_t *pool) { struct log_msg_baton *lmb = log_msg_baton; svn_error_t *err; /* If there was no tmpfile left, or there is no log message baton, return COMMIT_ERR. */ if ((! lmb) || (! lmb->tmpfile_left)) return commit_err; /* If there was no commit error, cleanup the tmpfile and return. */ if (! commit_err) return svn_io_remove_file2(lmb->tmpfile_left, FALSE, lmb->pool); /* There was a commit error; there is a tmpfile. Leave the tmpfile around, and add message about its presence to the commit error chain. Then return COMMIT_ERR. If the conversion from UTF-8 to native encoding fails, we have to compose that error with the commit error chain, too. */ err = svn_error_createf(commit_err->apr_err, NULL, _(" '%s'"), svn_dirent_local_style(lmb->tmpfile_left, pool)); svn_error_compose(commit_err, svn_error_create(commit_err->apr_err, err, _("Your commit message was left in " "a temporary file:"))); return commit_err; }
svn_error_t * svn_wc_set_adm_dir(const char *name, apr_pool_t *pool) { /* This is the canonical list of administrative directory names. FIXME: An identical list is used in libsvn_subr/opt.c:svn_opt__args_to_target_array(), but that function can't use this list, because that use would create a circular dependency between libsvn_wc and libsvn_subr. Make sure changes to the lists are always synchronized! */ static const char *valid_dir_names[] = { default_adm_dir_name, "_svn", NULL }; const char **dir_name; for (dir_name = valid_dir_names; *dir_name; ++dir_name) if (0 == strcmp(name, *dir_name)) { /* Use the pointer to the statically allocated string constant, to avoid potential pool lifetime issues. */ adm_dir_name = *dir_name; return SVN_NO_ERROR; } return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, _("'%s' is not a valid administrative " "directory name"), svn_dirent_local_style(name, pool)); }
/* This implements the svn_proplist_receiver_t interface, printing XML to stdout. */ static svn_error_t * proplist_receiver_xml(void *baton, const char *path, apr_hash_t *prop_hash, apr_pool_t *pool) { svn_cl__opt_state_t *opt_state = ((proplist_baton_t *)baton)->opt_state; svn_boolean_t is_url = ((proplist_baton_t *)baton)->is_url; svn_stringbuf_t *sb = NULL; const char *name_local; if (! is_url) name_local = svn_dirent_local_style(path, pool); else name_local = path; /* "<target ...>" */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "target", "path", name_local, NULL); SVN_ERR(svn_cl__print_xml_prop_hash(&sb, prop_hash, (! opt_state->verbose), pool)); /* "</target>" */ svn_xml_make_close_tag(&sb, pool, "target"); return svn_cl__error_checked_fputs(sb->data, stdout); }
svn_error_t * svn_repos__hooks_post_commit(svn_repos_t *repos, svn_revnum_t rev, apr_pool_t *pool) { const char *hook = svn_repos_post_commit_hook(repos, pool); svn_boolean_t broken_link; if ((hook = check_hook_cmd(hook, &broken_link, pool)) && broken_link) { return hook_symlink_error(hook); } else if (hook) { const char *args[4]; args[0] = hook; args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool); args[2] = apr_psprintf(pool, "%ld", rev); args[3] = NULL; SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_COMMIT, hook, args, repos->hooks_env, NULL, pool)); } return SVN_NO_ERROR; }
/* Called by status-cmd.c */ svn_error_t * svn_cl__print_status(const char *path, const svn_client_status_t *status, svn_boolean_t detailed, svn_boolean_t show_last_committed, svn_boolean_t skip_unrecognized, svn_boolean_t repos_locks, unsigned int *text_conflicts, unsigned int *prop_conflicts, unsigned int *tree_conflicts, svn_client_ctx_t *ctx, apr_pool_t *pool) { if (! status || (skip_unrecognized && !(status->versioned || status->conflicted || status->node_status == svn_wc_status_external)) || (status->node_status == svn_wc_status_none && status->repos_node_status == svn_wc_status_none)) return SVN_NO_ERROR; return print_status(svn_dirent_local_style(path, pool), detailed, show_last_committed, repos_locks, status, text_conflicts, prop_conflicts, tree_conflicts, ctx, pool); }
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; }
svn_error_t * svn_client__can_delete(const char *path, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { svn_opt_revision_t revision; svn_node_kind_t external_kind; const char *defining_abspath; const char* local_abspath; revision.kind = svn_opt_revision_unspecified; SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); /* A file external should not be deleted since the file external is implemented as a switched file and it would delete the file the file external is switched to, which is not the behavior the user would probably want. */ SVN_ERR(svn_wc__read_external_info(&external_kind, &defining_abspath, NULL, NULL, NULL, ctx->wc_ctx, local_abspath, local_abspath, TRUE, scratch_pool, scratch_pool)); if (external_kind != svn_node_none) return svn_error_createf(SVN_ERR_WC_CANNOT_DELETE_FILE_EXTERNAL, NULL, _("Cannot remove the external at '%s'; " "please edit or delete the svn:externals " "property on '%s'"), svn_dirent_local_style(local_abspath, scratch_pool), svn_dirent_local_style(defining_abspath, scratch_pool)); /* Use an infinite-depth status check to see if there's anything in or under PATH which would make it unsafe for deletion. The status callback function find_undeletables() makes the determination, returning an error if it finds anything that shouldn't be deleted. */ return svn_error_trace(svn_client_status5(NULL, ctx, path, &revision, svn_depth_infinity, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, find_undeletables, NULL, scratch_pool)); }
svn_error_t * svn_wc__db_util_open_db(svn_sqlite__db_t **sdb, const char *dir_abspath, const char *sdb_fname, svn_sqlite__mode_t smode, svn_boolean_t exclusive, const char *const *my_statements, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *sdb_abspath = svn_wc__adm_child(dir_abspath, sdb_fname, scratch_pool); if (smode != svn_sqlite__mode_rwcreate) { svn_node_kind_t kind; /* A file stat is much cheaper then a failed database open handled by SQLite. */ SVN_ERR(svn_io_check_path(sdb_abspath, &kind, scratch_pool)); if (kind != svn_node_file) return svn_error_createf(APR_ENOENT, NULL, _("Working copy database '%s' not found"), svn_dirent_local_style(sdb_abspath, scratch_pool)); } #ifndef WIN32 else { apr_file_t *f; /* A standard SQLite build creates a DB with mode 644 ^ !umask which means the file doesn't have group/world write access even when umask allows it. By ensuring the file exists before SQLite gets involved we give it the permissions allowed by umask. */ SVN_ERR(svn_io_file_open(&f, sdb_abspath, (APR_READ | APR_WRITE | APR_CREATE), APR_OS_DEFAULT, scratch_pool)); SVN_ERR(svn_io_file_close(f, scratch_pool)); } #endif SVN_ERR(svn_sqlite__open(sdb, sdb_abspath, smode, my_statements ? my_statements : statements, 0, NULL, result_pool, scratch_pool)); if (exclusive) SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_PRAGMA_LOCKING_MODE)); SVN_ERR(svn_sqlite__create_scalar_function(*sdb, "relpath_depth", 1, relpath_depth_sqlite, NULL)); return SVN_NO_ERROR; }
/* Called by status-cmd.c */ svn_error_t * svn_cl__print_status(const char *cwd_abspath, const char *path, const svn_client_status_t *status, svn_boolean_t suppress_externals_placeholders, svn_boolean_t detailed, svn_boolean_t show_last_committed, svn_boolean_t skip_unrecognized, svn_boolean_t repos_locks, unsigned int *text_conflicts, unsigned int *prop_conflicts, unsigned int *tree_conflicts, svn_client_ctx_t *ctx, apr_pool_t *pool) { if (! status || (skip_unrecognized && !(status->versioned || status->conflicted || status->node_status == svn_wc_status_external)) || (status->node_status == svn_wc_status_none && status->repos_node_status == svn_wc_status_none)) return SVN_NO_ERROR; /* If we're trying not to print boring "X /path/to/external" lines..." */ if (suppress_externals_placeholders) { /* ... skip regular externals unmodified in the repository. */ if ((status->node_status == svn_wc_status_external) && (status->repos_node_status == svn_wc_status_none) && (! status->conflicted)) return SVN_NO_ERROR; /* ... skip file externals that aren't modified locally or remotely, changelisted, or locked (in either sense of the word). */ if ((status->file_external) && (status->repos_node_status == svn_wc_status_none) && ((status->node_status == svn_wc_status_normal) || (status->node_status == svn_wc_status_none)) && ((status->prop_status == svn_wc_status_normal) || (status->prop_status == svn_wc_status_none)) && (! status->changelist) && (! status->lock) && (! status->wc_is_locked) && (! status->conflicted)) return SVN_NO_ERROR; } return print_status(cwd_abspath, svn_dirent_local_style(path, pool), detailed, show_last_committed, repos_locks, status, text_conflicts, prop_conflicts, tree_conflicts, ctx, pool); }
/* An svn_wc_status_func4_t callback function for finding status structures which are not safely deletable. */ static svn_error_t * find_undeletables(void *baton, const char *local_abspath, const svn_wc_status3_t *status, apr_pool_t *pool) { if (status->node_status == svn_wc_status_missing) { struct can_delete_baton_t *cdt = baton; if (strcmp(cdt->root_abspath, local_abspath) == 0) cdt->target_missing = TRUE; } /* Check for error-ful states. */ if (status->node_status == svn_wc_status_obstructed) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("'%s' is in the way of the resource " "actually under version control"), svn_dirent_local_style(local_abspath, pool)); else if (! status->versioned) return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("'%s' is not under version control"), svn_dirent_local_style(local_abspath, pool)); else if ((status->node_status == svn_wc_status_added || status->node_status == svn_wc_status_replaced) && status->text_status == svn_wc_status_normal && (status->prop_status == svn_wc_status_normal || status->prop_status == svn_wc_status_none)) { /* Unmodified copy. Go ahead, remove it */ } else if (status->node_status != svn_wc_status_normal && status->node_status != svn_wc_status_deleted && status->node_status != svn_wc_status_missing) return svn_error_createf(SVN_ERR_CLIENT_MODIFIED, NULL, _("'%s' has local modifications -- commit or " "revert them first"), svn_dirent_local_style(local_abspath, pool)); return SVN_NO_ERROR; }
/* Return a string of the form "PATH_OR_URL@REVISION". */ static const char * path_for_display(const char *path_or_url, const svn_opt_revision_t *revision, apr_pool_t *pool) { const char *rev_str = svn_opt__revision_to_string(revision, pool); if (! svn_path_is_url(path_or_url)) path_or_url = svn_dirent_local_style(path_or_url, pool); return apr_psprintf(pool, "%s@%s", path_or_url, rev_str); }
const char * svn_cl__local_style_skip_ancestor(const char *parent_path, const char *path, apr_pool_t *pool) { const char *relpath = NULL; if (parent_path) relpath = svn_dirent_skip_ancestor(parent_path, path); return svn_dirent_local_style(relpath ? relpath : path, pool); }
svn_error_t * svn_cl__propset_print_binary_mime_type_warning(apr_array_header_t *targets, const char *propname, const svn_string_t *propval, apr_pool_t *scratch_pool) { if (strcmp(propname, SVN_PROP_MIME_TYPE) == 0) { apr_pool_t *iterpool = svn_pool_create(scratch_pool); int i; for (i = 0; i < targets->nelts; i++) { const char *detected_mimetype; const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *local_abspath; const svn_string_t *canon_propval; svn_node_kind_t node_kind; svn_pool_clear(iterpool); SVN_ERR(svn_dirent_get_absolute(&local_abspath, target, iterpool)); SVN_ERR(svn_io_check_path(local_abspath, &node_kind, iterpool)); if (node_kind != svn_node_file) continue; SVN_ERR(svn_wc_canonicalize_svn_prop(&canon_propval, propname, propval, local_abspath, svn_node_file, FALSE, NULL, NULL, iterpool)); if (svn_mime_type_is_binary(canon_propval->data)) { SVN_ERR(svn_io_detect_mimetype2(&detected_mimetype, local_abspath, NULL, iterpool)); if (detected_mimetype == NULL || !svn_mime_type_is_binary(detected_mimetype)) svn_error_clear(svn_cmdline_fprintf(stderr, iterpool, _("svn: warning: '%s' is a binary mime-type but file '%s' " "looks like text; diff, merge, blame, and other " "operations will stop working on this file\n"), canon_propval->data, svn_dirent_local_style(local_abspath, iterpool))); } } svn_pool_destroy(iterpool); }
/* Get the format version from a wc-1 directory. If it is not a working copy directory, then it sets VERSION to zero and returns no error. */ static svn_error_t * get_old_version(int *version, const char *abspath, apr_pool_t *scratch_pool) { svn_error_t *err; const char *format_file_path; svn_node_kind_t kind; /* Try reading the format number from the entries file. */ format_file_path = svn_wc__adm_child(abspath, SVN_WC__ADM_ENTRIES, scratch_pool); /* Since trying to open a non-existent file is quite expensive, try a quick stat call first. In wc-ng w/cs, this will be an early exit. */ SVN_ERR(svn_io_check_path(format_file_path, &kind, scratch_pool)); if (kind == svn_node_none) { *version = 0; return SVN_NO_ERROR; } err = svn_io_read_version_file(version, format_file_path, scratch_pool); if (err == NULL) return SVN_NO_ERROR; if (err->apr_err != SVN_ERR_BAD_VERSION_FILE_FORMAT && !APR_STATUS_IS_ENOENT(err->apr_err) && !APR_STATUS_IS_ENOTDIR(err->apr_err)) return svn_error_createf(SVN_ERR_WC_MISSING, err, _("'%s' does not exist"), svn_dirent_local_style(abspath, scratch_pool)); svn_error_clear(err); /* This must be a really old working copy! Fall back to reading the format file. Note that the format file might not exist in newer working copies (format 7 and higher), but in that case, the entries file should have contained the format number. */ format_file_path = svn_wc__adm_child(abspath, SVN_WC__ADM_FORMAT, scratch_pool); err = svn_io_read_version_file(version, format_file_path, scratch_pool); if (err == NULL) return SVN_NO_ERROR; /* Whatever error may have occurred... we can just ignore. This is not a working copy directory. Signal the caller. */ svn_error_clear(err); *version = 0; return SVN_NO_ERROR; }
svn_error_t * svn_repos__hooks_post_revprop_change(svn_repos_t *repos, apr_hash_t *hooks_env, svn_revnum_t rev, const char *author, const char *name, const svn_string_t *old_value, char action, apr_pool_t *pool) { const char *hook = svn_repos_post_revprop_change_hook(repos, pool); svn_boolean_t broken_link; if ((hook = check_hook_cmd(hook, &broken_link, pool)) && broken_link) { return hook_symlink_error(hook); } else if (hook) { const char *args[7]; apr_file_t *stdin_handle = NULL; char action_string[2]; /* Pass the old value as stdin to hook */ if (old_value) SVN_ERR(create_temp_file(&stdin_handle, old_value, pool)); else SVN_ERR(svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME, APR_READ, APR_OS_DEFAULT, pool)); action_string[0] = action; action_string[1] = '\0'; args[0] = hook; args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool); args[2] = apr_psprintf(pool, "%ld", rev); args[3] = author ? author : ""; args[4] = name; args[5] = action_string; args[6] = NULL; SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_REVPROP_CHANGE, hook, args, hooks_env, stdin_handle, pool)); SVN_ERR(svn_io_file_close(stdin_handle, pool)); } return SVN_NO_ERROR; }
/* Set *NAME_P to the UTF-8 representation of directory entry NAME. * NAME is in the internal encoding used by APR; PARENT is in * UTF-8 and in internal (not local) style. * * Use PARENT only for generating an error string if the conversion * fails because NAME could not be represented in UTF-8. In that * case, return a two-level error in which the outer error's message * mentions PARENT, but the inner error's message does not mention * NAME (except possibly in hex) since NAME may not be printable. * Such a compound error at least allows the user to go looking in the * right directory for the problem. * * If there is any other error, just return that error directly. * * If there is any error, the effect on *NAME_P is undefined. * * *NAME_P and NAME may refer to the same storage. */ static svn_error_t * entry_name_to_utf8(const char **name_p, const char *name, const char *parent, apr_pool_t *pool) { svn_error_t *err = svn_path_cstring_to_utf8(name_p, name, pool); if (err && err->apr_err == APR_EINVAL) { return svn_error_createf(err->apr_err, err, _("Error converting entry " "in directory '%s' to UTF-8"), svn_dirent_local_style(parent, pool)); } return err; }
/* Go up the directory tree from LOCAL_ABSPATH, looking for a versioned * directory. If found, return its path in *EXISTING_PARENT_ABSPATH. * Otherwise, return SVN_ERR_CLIENT_NO_VERSIONED_PARENT. */ static svn_error_t * find_existing_parent(const char **existing_parent_abspath, svn_client_ctx_t *ctx, const char *local_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_node_kind_t kind; const char *parent_abspath; svn_wc_context_t *wc_ctx = ctx->wc_ctx; SVN_ERR(svn_wc_read_kind(&kind, wc_ctx, local_abspath, FALSE, scratch_pool)); if (kind == svn_node_dir) { svn_boolean_t is_deleted; SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath, scratch_pool)); if (!is_deleted) { *existing_parent_abspath = apr_pstrdup(result_pool, local_abspath); return SVN_NO_ERROR; } } if (svn_dirent_is_root(local_abspath, strlen(local_abspath))) return svn_error_create(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL, NULL); if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool), scratch_pool)) return svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED, NULL, _("'%s' ends in a reserved name"), svn_dirent_local_style(local_abspath, scratch_pool)); parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool); if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); SVN_ERR(find_existing_parent(existing_parent_abspath, ctx, parent_abspath, result_pool, scratch_pool)); return SVN_NO_ERROR; }