#include <stdarg.h>
#include <apr_pools.h>
#include <apr_file_io.h>
#include <apr_strings.h>
#include "svn_types.h"
#include "svn_error.h"
#include "svn_io.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_hash.h"
#include "wc.h"
#include "adm_files.h"
#include "entries.h"
#include "lock.h"
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
static const char default_adm_dir_name[] = ".svn";
static const char *adm_dir_name = default_adm_dir_name;
svn_boolean_t
svn_wc_is_adm_dir(const char *name, apr_pool_t *pool)
{
return (0 == strcmp(name, adm_dir_name)
|| 0 == strcmp(name, default_adm_dir_name));
}
const char *
svn_wc_get_adm_dir(apr_pool_t *pool)
{
return adm_dir_name;
}
svn_error_t *
svn_wc_set_adm_dir(const char *name, apr_pool_t *pool)
{
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))
{
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));
}
static const char *
simple_extend(const char *adm_path,
svn_boolean_t use_tmp,
const char *subdir,
const char *child,
const char *extension,
apr_pool_t *result_pool)
{
if (subdir)
child = svn_dirent_join(subdir, child, result_pool);
if (extension)
child = apr_pstrcat(result_pool, child, extension, (char *)NULL);
if (use_tmp)
return svn_dirent_join_many(result_pool,
adm_path,
adm_dir_name,
SVN_WC__ADM_TMP,
child,
NULL);
return svn_dirent_join_many(result_pool,
adm_path,
adm_dir_name,
child,
NULL);
}
const char *svn_wc__adm_child(const char *path,
const char *child,
apr_pool_t *result_pool)
{
return simple_extend(path, FALSE, NULL, child, NULL, result_pool);
}
svn_boolean_t
svn_wc__adm_area_exists(const char *adm_abspath,
apr_pool_t *pool)
{
const char *path = svn_wc__adm_child(adm_abspath, NULL, pool);
svn_node_kind_t kind;
svn_error_t *err;
err = svn_io_check_path(path, &kind, pool);
if (err)
{
svn_error_clear(err);
return FALSE;
}
return kind != svn_node_none;
}
static svn_error_t *
make_adm_subdir(const char *path,
const char *subdir,
svn_boolean_t tmp,
apr_pool_t *pool)
{
const char *fullpath;
fullpath = simple_extend(path, tmp, NULL, subdir, NULL, pool);
return svn_io_dir_make(fullpath, APR_OS_DEFAULT, pool);
}
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));
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)
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;
}
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));
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)
{
*contents = NULL;
return SVN_NO_ERROR;
}
else if (status == svn_wc__db_status_not_present)
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__open_adm_stream(svn_stream_t **stream,
const char *dir_abspath,
const char *fname,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *local_abspath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
local_abspath = svn_wc__adm_child(dir_abspath, fname, scratch_pool);
return svn_error_trace(svn_stream_open_readonly(stream, local_abspath,
result_pool, scratch_pool));
}
svn_error_t *
svn_wc__open_writable_base(svn_stream_t **stream,
const char **temp_base_abspath,
svn_checksum_t **md5_checksum,
svn_checksum_t **sha1_checksum,
svn_wc__db_t *db,
const char *wri_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *temp_dir_abspath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_pristine_get_tempdir(&temp_dir_abspath, db, wri_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_stream_open_unique(stream,
temp_base_abspath,
temp_dir_abspath,
svn_io_file_del_none,
result_pool, scratch_pool));
if (md5_checksum)
*stream = svn_stream_checksummed2(*stream, NULL, md5_checksum,
svn_checksum_md5, FALSE, result_pool);
if (sha1_checksum)
*stream = svn_stream_checksummed2(*stream, NULL, sha1_checksum,
svn_checksum_sha1, FALSE, result_pool);
return SVN_NO_ERROR;
}
static svn_error_t *
init_adm_tmp_area(const char *path, apr_pool_t *pool)
{
SVN_ERR(make_adm_subdir(path, SVN_WC__ADM_TMP, FALSE, pool));
return SVN_NO_ERROR;
}
static svn_error_t *
init_adm(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t initial_rev,
svn_depth_t depth,
apr_pool_t *pool)
{
SVN_ERR(svn_io_dir_make_hidden(svn_wc__adm_child(local_abspath, NULL, pool),
APR_OS_DEFAULT, pool));
SVN_ERR(make_adm_subdir(local_abspath, SVN_WC__ADM_PRISTINE, FALSE, pool));
SVN_ERR(init_adm_tmp_area(local_abspath, pool));
SVN_ERR(svn_wc__db_init(db, local_abspath,
repos_relpath, repos_root_url, repos_uuid,
initial_rev, depth,
pool));
SVN_ERR(svn_io_file_create(svn_wc__adm_child(local_abspath,
SVN_WC__ADM_ENTRIES,
pool),
SVN_WC__NON_ENTRIES_STRING,
pool));
SVN_ERR(svn_io_file_create(svn_wc__adm_child(local_abspath,
SVN_WC__ADM_FORMAT,
pool),
SVN_WC__NON_ENTRIES_STRING,
pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__internal_ensure_adm(svn_wc__db_t *db,
const char *local_abspath,
const char *url,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
int format;
const char *repos_relpath;
svn_wc__db_status_t status;
const char *db_repos_relpath, *db_repos_root_url, *db_repos_uuid;
svn_revnum_t db_revision;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(url != NULL);
SVN_ERR_ASSERT(repos_root_url != NULL);
SVN_ERR_ASSERT(repos_uuid != NULL);
SVN_ERR_ASSERT(svn_uri__is_ancestor(repos_root_url, url));
SVN_ERR(svn_wc__internal_check_wc(&format, db, local_abspath, TRUE,
scratch_pool));
repos_relpath = svn_uri__is_child(repos_root_url, url, scratch_pool);
if (repos_relpath == NULL)
repos_relpath = "";
if (format == 0)
return svn_error_trace(init_adm(db, local_abspath,
repos_relpath, repos_root_url, repos_uuid,
revision, depth, scratch_pool));
SVN_ERR(svn_wc__db_read_info(&status, NULL,
&db_revision, &db_repos_relpath,
&db_repos_root_url, &db_repos_uuid,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, local_abspath, scratch_pool, scratch_pool));
if (status != svn_wc__db_status_deleted
&& status != svn_wc__db_status_not_present)
{
if (db_revision != revision)
return
svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("Revision %ld doesn't match existing "
"revision %ld in '%s'"),
revision, db_revision, local_abspath);
if (!db_repos_root_url)
{
if (status == svn_wc__db_status_added)
SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
&db_repos_relpath,
&db_repos_root_url,
&db_repos_uuid,
NULL, NULL, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
else
SVN_ERR(svn_wc__db_scan_base_repos(&db_repos_relpath,
&db_repos_root_url,
&db_repos_uuid,
db, local_abspath,
scratch_pool, scratch_pool));
}
if (strcmp(db_repos_uuid, repos_uuid)
|| strcmp(db_repos_root_url, repos_root_url)
|| !svn_relpath__is_ancestor(db_repos_relpath, repos_relpath))
{
const char *copyfrom_root_url, *copyfrom_repos_relpath;
SVN_ERR(svn_wc__internal_get_copyfrom_info(©from_root_url,
©from_repos_relpath,
NULL, NULL, NULL,
db, local_abspath,
scratch_pool,
scratch_pool));
if (copyfrom_root_url == NULL
|| strcmp(copyfrom_root_url, repos_root_url)
|| strcmp(copyfrom_repos_relpath, repos_relpath))
return
svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("URL '%s' (uuid: '%s') doesn't match existing "
"URL '%s' (uuid: '%s') in '%s'"),
url,
db_repos_uuid,
svn_path_url_add_component2(db_repos_root_url,
db_repos_relpath,
scratch_pool),
repos_uuid,
local_abspath);
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_ensure_adm4(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const char *url,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
return svn_error_trace(
svn_wc__internal_ensure_adm(wc_ctx->db, local_abspath, url, repos_root_url,
repos_uuid, revision, depth, scratch_pool));
}
svn_error_t *
svn_wc__adm_destroy(svn_wc__db_t *db,
const char *dir_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
const char *adm_abspath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
SVN_ERR(svn_wc__db_get_wcroot(&adm_abspath, db, dir_abspath,
scratch_pool, scratch_pool));
if (strcmp(adm_abspath, dir_abspath) == 0)
{
SVN_ERR(svn_wc__db_drop_root(db, adm_abspath, scratch_pool));
SVN_ERR(svn_io_remove_dir2(svn_wc__adm_child(adm_abspath, NULL,
scratch_pool),
FALSE,
cancel_func, cancel_baton,
scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__adm_cleanup_tmp_area(svn_wc__db_t *db,
const char *adm_abspath,
apr_pool_t *scratch_pool)
{
const char *tmp_path;
SVN_ERR_ASSERT(svn_dirent_is_absolute(adm_abspath));
SVN_ERR(svn_wc__write_check(db, adm_abspath, scratch_pool));
tmp_path = svn_wc__adm_child(adm_abspath, SVN_WC__ADM_TMP, scratch_pool);
SVN_ERR(svn_io_remove_dir2(tmp_path, TRUE, NULL, NULL, scratch_pool));
return svn_error_trace(init_adm_tmp_area(adm_abspath, scratch_pool));
}
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 ,
TRUE ,
TRUE ,
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;
}