📄 adm_files.c
字号:
return sync_adm_file (parent_dir, NULL, pool,
SVN_WC__ADM_DIR_PROP_BASE, NULL);
else
return sync_adm_file (parent_dir, SVN_WC__BASE_EXT, pool,
SVN_WC__ADM_PROP_BASE, base_name, NULL);
}
else if (wcprops)
{
if (kind == svn_node_dir)
return sync_adm_file (parent_dir, NULL, pool,
SVN_WC__ADM_DIR_WCPROPS, NULL);
else
return sync_adm_file (parent_dir, SVN_WC__BASE_EXT, pool,
SVN_WC__ADM_WCPROPS, base_name, NULL);
}
else /* plain old property file */
{
if (kind == svn_node_dir)
return sync_adm_file (parent_dir, NULL, pool,
SVN_WC__ADM_DIR_PROPS, NULL);
else
return sync_adm_file (parent_dir, SVN_WC__WORK_EXT, pool,
SVN_WC__ADM_PROPS, base_name, NULL);
}
}
/*** Checking for and creating administrative subdirs. ***/
/* Set *EXISTS to iff there's an adm area for PATH, and it matches URL
* and REVISION. If there's no adm area, set *EXISTS to false; if
* there's an adm area but it doesn't match URL and REVISION, then
* return error and don't touch *EXISTS.
*
* ### These semantics are totally bizarre. One wonders what the
* ### callers' real needs are. In the long term, this function
* ### should probably be unified with svn_wc_check_wc.
*/
static svn_error_t *
check_adm_exists (svn_boolean_t *exists,
const char *path,
const char *url,
svn_revnum_t revision,
apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
svn_node_kind_t kind;
svn_boolean_t dir_exists = FALSE, wc_exists = FALSE;
const char *tmp_path;
/** Step 1: check that the directory exists. **/
tmp_path = extend_with_adm_name (path, NULL, 0, pool, NULL);
SVN_ERR (svn_io_check_path (tmp_path, &kind, pool));
if (kind != svn_node_none && kind != svn_node_dir)
{
/* If got an error other than dir non-existence, then
something's weird and we should return a genuine error. */
return svn_error_createf (APR_ENOTDIR, NULL,
_("'%s' is not a directory"), tmp_path);
}
else if (kind == svn_node_none)
{
dir_exists = FALSE;
}
else /* must be a dir. */
{
assert (kind == svn_node_dir);
dir_exists = TRUE;
}
/** Step 1. If no adm directory, then we're done. */
if (! dir_exists)
{
*exists = FALSE;
return SVN_NO_ERROR;
}
/** The directory exists, but is it a valid working copy yet?
Try step 2: checking that SVN_WC__ADM_FORMAT exists and that
it's not too high a format version for this code. **/
{
int wc_format;
err = svn_io_read_version_file
(&wc_format, svn_path_join (tmp_path, SVN_WC__ADM_FORMAT, pool), pool);
if (err)
{
svn_error_clear (err);
wc_exists = FALSE;
}
else
wc_exists = TRUE;
}
/** Step 3: now check that repos and ancestry are correct **/
if (wc_exists)
{
/* This is a bit odd. We have to open an access baton, which relies
on this being a working copy, in order to determine if this is a
working copy! */
svn_wc_adm_access_t *adm_access;
const svn_wc_entry_t *entry;
SVN_ERR (svn_wc_adm_open2 (&adm_access, NULL, path, FALSE, 0,
pool));
SVN_ERR (svn_wc_entry (&entry, path, adm_access, FALSE, pool));
SVN_ERR (svn_wc_adm_close (adm_access));
if (!entry)
return svn_error_createf (SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("No entry for '%s'"), path);
/* The revisions must match except when adding a directory with a
name that matches a directory scheduled for deletion. That's
because the deleted directory's administrative dir will still be
in place but will have an arbitrary revision. */
if (entry->revision != revision
&& !(entry->schedule == svn_wc_schedule_delete && revision == 0))
return
svn_error_createf
(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("Revision %ld doesn't match existing revision %ld in '%s'"),
revision, entry->revision, path);
/** ### comparing URLs, should they be canonicalized first? */
if (strcmp (entry->url, url) != 0)
return
svn_error_createf
(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("URL '%s' doesn't match existing URL '%s' in '%s'"),
url, entry->url, path);
}
*exists = wc_exists;
return SVN_NO_ERROR;
}
static svn_error_t *
make_empty_adm (const char *path, apr_pool_t *pool)
{
path = extend_with_adm_name (path, NULL, 0, pool, NULL);
SVN_ERR (svn_io_dir_make_hidden (path, APR_OS_DEFAULT, pool));
return SVN_NO_ERROR;
}
/* Init an adm file with some contents.
Don't call this until a tmp area exists in adm. */
static svn_error_t *
init_adm_file (const char *path,
const char *thing,
const char *contents,
apr_pool_t *pool)
{
apr_file_t *f = NULL;
SVN_ERR (svn_wc__open_adm_file (&f, path, thing,
APR_WRITE | APR_CREATE, pool));
SVN_ERR (svn_io_file_write_full (f, contents,
strlen (contents), NULL, pool));
SVN_ERR (svn_wc__close_adm_file (f, path, thing, 1, pool));
return SVN_NO_ERROR;
}
static svn_error_t *
init_adm_tmp_area (svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
/* Default perms */
apr_fileperms_t perms = APR_OS_DEFAULT;
/* SVN_WC__ADM_TMP */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_TMP,
svn_node_dir, perms, 0, pool));
/* SVN_WC__ADM_TMP/SVN_WC__ADM_TEXT_BASE */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_TEXT_BASE,
svn_node_dir, perms, 1, pool));
/* SVN_WC__ADM_TMP/SVN_WC__ADM_PROP_BASE */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_PROP_BASE,
svn_node_dir, perms, 1, pool));
/* SVN_WC__ADM_TMP/SVN_WC__ADM_PROPS */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_PROPS,
svn_node_dir, perms, 1, pool));
/* SVN_WC__ADM_TMP/SVN_WC__ADM_WCPROPS */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_WCPROPS,
svn_node_dir, perms, 1, pool));
return SVN_NO_ERROR;
}
/* Set up a new adm area for PATH, with URL as the ancestor url, and
INITIAL_REV as the starting revision. The entries file starts out
marked as 'incomplete. The adm area starts out locked; remember to
unlock it when done. */
static svn_error_t *
init_adm (const char *path,
const char *uuid,
const char *url,
svn_revnum_t initial_rev,
apr_pool_t *pool)
{
svn_wc_adm_access_t *adm_access;
/* Default perms */
apr_fileperms_t perms = APR_OS_DEFAULT;
/* Initial contents for certain adm files. */
const char *readme_contents =
"This is a Subversion working copy administrative directory."
APR_EOL_STR
"Visit http://subversion.tigris.org/ for more information."
APR_EOL_STR;
/* First, make an empty administrative area. */
make_empty_adm (path, pool);
/* Lock it immediately. Theoretically, no compliant wc library
would ever consider this an adm area until a README file were
present... but locking it is still appropriately paranoid. */
SVN_ERR (svn_wc__adm_pre_open (&adm_access, path, pool));
/** Make subdirectories. ***/
/* SVN_WC__ADM_TEXT_BASE */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_TEXT_BASE,
svn_node_dir, perms, 0, pool));
/* SVN_WC__ADM_PROP_BASE */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_PROP_BASE,
svn_node_dir, perms, 0, pool));
/* SVN_WC__ADM_PROPS */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_PROPS,
svn_node_dir, perms, 0, pool));
/* SVN_WC__ADM_WCPROPS */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_WCPROPS,
svn_node_dir, perms, 0, pool));
/** Init the tmp area. ***/
SVN_ERR (init_adm_tmp_area (adm_access, pool));
/** Initialize each administrative file. */
/* SVN_WC__ADM_ENTRIES */
SVN_ERR (svn_wc__entries_init (path, uuid, url, initial_rev, pool));
/* SVN_WC__ADM_EMPTY_FILE exists because sometimes an readable, empty
file is required (in the repository diff for example). Creating such a
file temporarily, only to delete it again, would appear to be less
efficient than just having one around. It doesn't take up much space
after all. */
SVN_ERR (svn_wc__make_adm_thing (adm_access, SVN_WC__ADM_EMPTY_FILE,
svn_node_file,
APR_UREAD | APR_GREAD | APR_WREAD,
0, pool));
/* SVN_WC__ADM_README */
SVN_ERR (init_adm_file (path, SVN_WC__ADM_README, readme_contents, pool));
/* THIS FILE MUST BE CREATED LAST:
After this exists, the dir is considered complete. */
SVN_ERR (svn_io_write_version_file
(extend_with_adm_name (path, NULL, FALSE, pool,
SVN_WC__ADM_FORMAT, NULL),
SVN_WC__VERSION, pool));
/* Now unlock it. It's now a valid working copy directory, that
just happens to be at revision 0. */
SVN_ERR (svn_wc_adm_close (adm_access));
/* Else no problems, we're outta here. */
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_ensure_adm (const char *path,
const char *uuid,
const char *url,
svn_revnum_t revision,
apr_pool_t *pool)
{
svn_boolean_t exists_already;
SVN_ERR (check_adm_exists (&exists_already, path, url, revision, pool));
return (exists_already ? SVN_NO_ERROR :
init_adm (path, uuid, url, revision, pool));
}
svn_error_t *
svn_wc__adm_destroy (svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
const char *path;
SVN_ERR (svn_wc__adm_write_check (adm_access));
/* Well, the coast is clear for blowing away the administrative
directory, which also removes the lock file */
path = extend_with_adm_name (svn_wc_adm_access_path (adm_access),
NULL, FALSE, pool, NULL);
SVN_ERR (svn_io_remove_dir (path, pool));
SVN_ERR (svn_wc_adm_close (adm_access));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__adm_cleanup_tmp_area (svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
const char *tmp_path;
SVN_ERR (svn_wc__adm_write_check (adm_access));
/* Get the path to the tmp area, and blow it away. */
tmp_path = extend_with_adm_name (svn_wc_adm_access_path (adm_access),
NULL, 0, pool, SVN_WC__ADM_TMP, NULL);
SVN_ERR (svn_io_remove_dir (tmp_path, pool));
/* Now, rebuild the tmp area. */
SVN_ERR (init_adm_tmp_area (adm_access, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_create_tmp_file (apr_file_t **fp,
const char *path,
svn_boolean_t delete_on_close,
apr_pool_t *pool)
{
const char *ignored_filename;
/* Use a self-explanatory name for the file :-) . */
path = svn_wc__adm_path (path, TRUE, pool, "tempfile", NULL);
/* Open a unique file; use APR_DELONCLOSE. */
SVN_ERR (svn_io_open_unique_file (fp, &ignored_filename,
path, ".tmp", delete_on_close, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__prep_file_for_replacement (const char *path,
svn_boolean_t ignore_enoent,
apr_pool_t *pool)
{
/* On Unix a read-only file can still be removed or replaced because
this is really an edit of the parent directory, not of the file
itself. Windows apparently has different semantics, and so
when the svn_io_set_file_read_write() call was temporarily
removed in revision 5663, Subversion stopped working on Windows.
However, the svn_io_set_file_read_write() call sets all write
permissions on Unix, which is undesireable. Since it is unnecessary
to make the file writeable, do nothing to prep the file for replacement
on Unix. */
#ifdef WIN32
return svn_io_set_file_read_write (path, ignore_enoent, pool);
#endif /* WIN32 */
return SVN_NO_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -