#include <string.h>
#include <apr_pools.h>
#include <apr_file_io.h>
#include <apr_file_info.h>
#include <apr_time.h>
#include "svn_pools.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
#include "svn_time.h"
#include "svn_io.h"
#include "svn_props.h"
#include "wc.h"
#include "adm_files.h"
#include "props.h"
#include "translate.h"
#include "wc_db.h"
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
static svn_error_t *
compare_and_verify(svn_boolean_t *modified_p,
svn_wc__db_t *db,
const char *versioned_file_abspath,
svn_filesize_t versioned_file_size,
svn_stream_t *pristine_stream,
svn_filesize_t pristine_size,
svn_boolean_t has_props,
svn_boolean_t props_mod,
svn_boolean_t exact_comparison,
apr_pool_t *scratch_pool)
{
svn_boolean_t same;
svn_subst_eol_style_t eol_style;
const char *eol_str;
apr_hash_t *keywords;
svn_boolean_t special = FALSE;
svn_boolean_t need_translation;
SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_file_abspath));
if (props_mod)
has_props = TRUE;
if (has_props)
{
SVN_ERR(svn_wc__get_translate_info(&eol_style, &eol_str,
&keywords,
&special,
db, versioned_file_abspath, NULL,
!exact_comparison,
scratch_pool, scratch_pool));
need_translation = svn_subst_translation_required(eol_style, eol_str,
keywords, special,
TRUE);
}
else
need_translation = FALSE;
if (! need_translation
&& (versioned_file_size != pristine_size))
{
*modified_p = TRUE;
return svn_error_trace(svn_stream_close(pristine_stream));
}
#if 0
if (need_translation
&& !special
&& !props_mod
&& (keywords == NULL)
&& (versioned_file_size < pristine_file_size))
{
*modified_p = TRUE;
return svn_error_trace(svn_stream_close(pristine_stream));
}
#endif
if (need_translation)
{
svn_stream_t *v_stream;
if (special)
{
SVN_ERR(svn_subst_read_specialfile(&v_stream, versioned_file_abspath,
scratch_pool, scratch_pool));
}
else
{
SVN_ERR(svn_stream_open_readonly(&v_stream, versioned_file_abspath,
scratch_pool, scratch_pool));
if (!exact_comparison && need_translation)
{
if (eol_style == svn_subst_eol_style_native)
eol_str = SVN_SUBST_NATIVE_EOL_STR;
else if (eol_style != svn_subst_eol_style_fixed
&& eol_style != svn_subst_eol_style_none)
return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
v_stream = svn_subst_stream_translated(v_stream,
eol_str,
TRUE ,
keywords,
FALSE ,
scratch_pool);
}
else if (need_translation)
{
pristine_stream = svn_subst_stream_translated(pristine_stream,
eol_str, FALSE,
keywords, TRUE,
scratch_pool);
}
}
SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
scratch_pool));
}
else
{
svn_stream_t *v_stream;
SVN_ERR(svn_stream_open_readonly(&v_stream, versioned_file_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
scratch_pool));
}
*modified_p = (! same);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__internal_file_modified_p(svn_boolean_t *modified_p,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t exact_comparison,
apr_pool_t *scratch_pool)
{
svn_stream_t *pristine_stream;
svn_filesize_t pristine_size;
svn_wc__db_status_t status;
svn_wc__db_kind_t kind;
const svn_checksum_t *checksum;
svn_filesize_t recorded_size;
apr_time_t recorded_mod_time;
svn_boolean_t has_props;
svn_boolean_t props_mod;
const svn_io_dirent2_t *dirent;
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, &checksum, NULL, NULL, NULL,
NULL, NULL, NULL,
&recorded_size, &recorded_mod_time,
NULL, NULL, NULL, &has_props, &props_mod,
NULL, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
if (!checksum
|| (kind != svn_wc__db_kind_file)
|| ((status != svn_wc__db_status_normal)
&& (status != svn_wc__db_status_added)))
{
*modified_p = TRUE;
return SVN_NO_ERROR;
}
SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
scratch_pool, scratch_pool));
if (dirent->kind != svn_node_file)
{
*modified_p = FALSE;
return SVN_NO_ERROR;
}
if (! exact_comparison)
{
if (recorded_size != SVN_INVALID_FILESIZE
&& dirent->filesize != recorded_size)
goto compare_them;
if (recorded_mod_time != dirent->mtime)
goto compare_them;
*modified_p = FALSE;
return SVN_NO_ERROR;
}
compare_them:
SVN_ERR(svn_wc__db_pristine_read(&pristine_stream, &pristine_size,
db, local_abspath, checksum,
scratch_pool, scratch_pool));
{
svn_error_t *err;
err = compare_and_verify(modified_p, db,
local_abspath, dirent->filesize,
pristine_stream, pristine_size,
has_props, props_mod,
exact_comparison,
scratch_pool);
if (err && APR_STATUS_IS_EACCES(err->apr_err))
return svn_error_create(SVN_ERR_WC_PATH_ACCESS_DENIED, err, NULL);
else
SVN_ERR(err);
}
if (!*modified_p)
{
svn_boolean_t own_lock;
SVN_ERR(svn_wc__db_wclock_owns_lock(&own_lock, db, local_abspath, FALSE,
scratch_pool));
if (own_lock)
SVN_ERR(svn_wc__db_global_record_fileinfo(db, local_abspath,
dirent->filesize,
dirent->mtime,
scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_text_modified_p2(svn_boolean_t *modified_p,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t force_comparison,
apr_pool_t *scratch_pool)
{
return svn_wc__internal_file_modified_p(modified_p, wc_ctx->db,
local_abspath, FALSE, scratch_pool);
}
svn_error_t *
svn_wc__internal_conflicted_p(svn_boolean_t *text_conflicted_p,
svn_boolean_t *prop_conflicted_p,
svn_boolean_t *tree_conflicted_p,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_node_kind_t kind;
svn_wc__db_kind_t node_kind;
const apr_array_header_t *conflicts;
int i;
svn_boolean_t conflicted;
if (text_conflicted_p)
*text_conflicted_p = FALSE;
if (prop_conflicted_p)
*prop_conflicted_p = FALSE;
if (tree_conflicted_p)
*tree_conflicted_p = FALSE;
SVN_ERR(svn_wc__db_read_info(NULL, &node_kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &conflicted,
NULL, NULL, NULL, NULL, NULL, NULL,
db, local_abspath, scratch_pool,
scratch_pool));
if (!conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
scratch_pool, scratch_pool));
for (i = 0; i < conflicts->nelts; i++)
{
const svn_wc_conflict_description2_t *cd;
cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
switch (cd->kind)
{
case svn_wc_conflict_kind_text:
if (!text_conflicted_p || *text_conflicted_p)
break;
if (cd->base_abspath)
{
SVN_ERR(svn_io_check_path(cd->base_abspath, &kind,
scratch_pool));
*text_conflicted_p = (kind == svn_node_file);
if (*text_conflicted_p)
break;
}
if (cd->their_abspath)
{
SVN_ERR(svn_io_check_path(cd->their_abspath, &kind,
scratch_pool));
*text_conflicted_p = (kind == svn_node_file);
if (*text_conflicted_p)
break;
}
if (cd->my_abspath)
{
SVN_ERR(svn_io_check_path(cd->my_abspath, &kind,
scratch_pool));
*text_conflicted_p = (kind == svn_node_file);
}
break;
case svn_wc_conflict_kind_property:
if (!prop_conflicted_p || *prop_conflicted_p)
break;
if (cd->their_abspath)
{
SVN_ERR(svn_io_check_path(cd->their_abspath, &kind,
scratch_pool));
*prop_conflicted_p = (kind == svn_node_file);
}
break;
case svn_wc_conflict_kind_tree:
if (tree_conflicted_p)
*tree_conflicted_p = TRUE;
break;
default:
break;
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_conflicted_p3(svn_boolean_t *text_conflicted_p,
svn_boolean_t *prop_conflicted_p,
svn_boolean_t *tree_conflicted_p,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__internal_conflicted_p(text_conflicted_p,
prop_conflicted_p,
tree_conflicted_p,
wc_ctx->db,
local_abspath,
scratch_pool));
}
svn_error_t *
svn_wc__min_max_revisions(svn_revnum_t *min_revision,
svn_revnum_t *max_revision,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t committed,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__db_min_max_revisions(min_revision,
max_revision,
wc_ctx->db,
local_abspath,
committed,
scratch_pool));
}
svn_error_t *
svn_wc__is_sparse_checkout(svn_boolean_t *is_sparse_checkout,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__db_is_sparse_checkout(is_sparse_checkout,
wc_ctx->db,
local_abspath,
scratch_pool));
}
svn_error_t *
svn_wc__has_switched_subtrees(svn_boolean_t *is_switched,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
const char *trail_url,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__db_has_switched_subtrees(is_switched,
wc_ctx->db,
local_abspath,
trail_url,
scratch_pool));
}
svn_error_t *
svn_wc__has_local_mods(svn_boolean_t *is_modified,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__db_has_local_mods(is_modified,
wc_ctx->db,
local_abspath,
cancel_func,
cancel_baton,
scratch_pool));
}