📄 questions.c
字号:
/*
* questions.c: routines for asking questions about working copies
*
* ====================================================================
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
#include <string.h>
#include <apr_pools.h>
#include <apr_file_io.h>
#include <apr_time.h>
#include <apr_strings.h>
#include "svn_pools.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_hash.h"
#include "svn_path.h"
#include "svn_time.h"
#include "svn_wc.h"
#include "svn_io.h"
#include "wc.h"
#include "adm_files.h"
#include "questions.h"
#include "entries.h"
#include "svn_md5.h"
#include <apr_md5.h>
#include "svn_private_config.h"
/* ### todo: make this compare repository too? Or do so in parallel
code. See also adm_files.c:check_adm_exists(), which should
probably be merged with this. */
svn_error_t *
svn_wc_check_wc (const char *path,
int *wc_format,
apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
svn_node_kind_t kind;
SVN_ERR (svn_io_check_path (path, &kind, pool));
if (kind == svn_node_none)
{
return svn_error_createf
(APR_ENOENT, NULL, _("'%s' does not exist"), path);
}
else if (kind != svn_node_dir)
*wc_format = 0;
else /* okay, it's a directory, but is it a working copy? */
{
const char *format_file_path
= svn_wc__adm_path (path, FALSE, pool, SVN_WC__ADM_FORMAT, NULL);
err = svn_io_read_version_file (wc_format, format_file_path, pool);
if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
|| APR_STATUS_IS_ENOTDIR(err->apr_err)))
{
/* If the format file does not exist, then for our purposes
this is not a working copy, so return 0. */
svn_error_clear (err);
*wc_format = 0;
}
else if (err)
return err;
else
{
/* If we managed to read the format file we assume that we
are dealing with a real wc so we can return a nice
error. */
SVN_ERR (svn_wc__check_format (*wc_format, path, pool));
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__check_format (int wc_format, const char *path, apr_pool_t *pool)
{
if (wc_format < 2)
{
return svn_error_createf
(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
_("Working copy format of '%s' is too old (%d); "
"please check out your working copy again"),
path, wc_format);
}
else if (wc_format > SVN_WC__VERSION)
{
return svn_error_createf
(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
_("This client is too old to work with working copy '%s'; "
"please get a newer Subversion client"),
path);
}
return SVN_NO_ERROR;
}
/*** svn_wc_text_modified_p ***/
/* svn_wc_text_modified_p answers the question:
"Are the contents of F different than the contents of
.svn/text-base/F.svn-base?"
or
"Are the contents of .svn/props/xxx different than
.svn/prop-base/xxx.svn-base?"
In other words, we're looking to see if a user has made local
modifications to a file since the last update or commit.
Note: Assuming that F lives in a directory D at revision V, please
notice that we are *NOT* answering the question, "are the contents
of F different than revision V of F?" While F may be at a different
revision number than its parent directory, but we're only looking
for local edits on F, not for consistent directory revisions.
TODO: the logic of the routines on this page might change in the
future, as they bear some relation to the user interface. For
example, if a file is removed -- without telling subversion about
it -- how should subversion react? Should it copy the file back
out of text-base? Should it ask whether one meant to officially
mark it for removal?
*/
/* Is PATH's timestamp the same as the one recorded in our
`entries' file? Return the answer in EQUAL_P. TIMESTAMP_KIND
should be one of the enumerated type above. */
svn_error_t *
svn_wc__timestamps_equal_p (svn_boolean_t *equal_p,
const char *path,
svn_wc_adm_access_t *adm_access,
enum svn_wc__timestamp_kind timestamp_kind,
apr_pool_t *pool)
{
apr_time_t wfile_time, entrytime = 0;
const svn_wc_entry_t *entry;
/* Get the timestamp from the entries file */
SVN_ERR (svn_wc_entry (&entry, path, adm_access, FALSE, pool));
/* Can't compare timestamps for an unversioned file. */
if (entry == NULL)
return svn_error_createf
(SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("'%s' is not under version control"), path);
/* Get the timestamp from the working file and the entry */
if (timestamp_kind == svn_wc__text_time)
{
SVN_ERR (svn_io_file_affected_time (&wfile_time, path, pool));
entrytime = entry->text_time;
}
else if (timestamp_kind == svn_wc__prop_time)
{
const char *prop_path;
SVN_ERR (svn_wc__prop_path (&prop_path, path, adm_access, FALSE, pool));
SVN_ERR (svn_io_file_affected_time (&wfile_time, prop_path, pool));
entrytime = entry->prop_time;
}
if (! entrytime)
{
/* TODO: If either timestamp is inaccessible, the test cannot
return an answer. Assume that the timestamps are
different. */
*equal_p = FALSE;
return SVN_NO_ERROR;
}
{
/* Put the disk timestamp through a string conversion, so it's
at the same resolution as entry timestamps. */
/* This string conversion here may be goodness, but it does
nothing currently _and_ it is somewhat expensive _and_ it eats
memory _and_ it is tested for in the regression tests. But I
will only comment it out because I do not possess the guts to
remove it altogether. */
/*
const char *tstr = svn_time_to_cstring (wfile_time, pool);
SVN_ERR (svn_time_from_cstring (&wfile_time, tstr, pool));
*/
}
if (wfile_time == entrytime)
*equal_p = TRUE;
else
*equal_p = FALSE;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__versioned_file_modcheck (svn_boolean_t *modified_p,
const char *versioned_file,
svn_wc_adm_access_t *adm_access,
const char *base_file,
apr_pool_t *pool)
{
svn_boolean_t same;
const char *tmp_vfile;
svn_error_t *err = SVN_NO_ERROR, *err2 = SVN_NO_ERROR;
SVN_ERR (svn_wc_translated_file (&tmp_vfile, versioned_file, adm_access,
TRUE, pool));
err = svn_io_files_contents_same_p (&same, tmp_vfile, base_file, pool);
*modified_p = (! same);
if (tmp_vfile != versioned_file)
err2 = svn_io_remove_file (tmp_vfile, pool);
if (err)
{
if (err2)
svn_error_compose (err, err2);
return err;
}
return err2;
}
/* Set *MODIFIED_P to true if (after translation) VERSIONED_FILE
* differs from BASE_FILE, else to false if not. Also, verify that
* BASE_FILE matches the entry checksum for VERSIONED_FILE; if it
* does not match, return the error SVN_ERR_WC_CORRUPT_TEXT_BASE.
*
* ADM_ACCESS is an access baton for VERSIONED_FILE. Use POOL for
* temporary allocation.
*/
static svn_error_t *
compare_and_verify (svn_boolean_t *modified_p,
const char *versioned_file,
svn_wc_adm_access_t *adm_access,
const char *base_file,
apr_pool_t *pool)
{
const char *tmp_vfile;
svn_error_t *err = SVN_NO_ERROR, *err2 = SVN_NO_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -