📄 adm_files.c
字号:
/*
* adm_files.c: helper routines for handling files & dirs in the
* working copy administrative area (creating,
* deleting, opening, and closing). This is the only
* code that actually knows where administrative
* information is kept.
*
* ====================================================================
* 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 <stdarg.h>
#include <assert.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_file_io.h>
#include <apr_time.h>
#include <apr_strings.h>
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_hash.h"
#include "svn_io.h"
#include "svn_path.h"
#include "svn_wc.h"
#include "wc.h"
#include "adm_files.h"
#include "entries.h"
#include "svn_private_config.h"
/*** File names in the adm area. ***/
/* Return the path to something in PATH's administrative area.
*
* First, the adm subdir is appended to PATH as a component, then the
* "tmp" directory is added iff USE_TMP is set, then each of the
* varargs in AP (char *'s) is appended as a path component. The list
* must be terminated with a NULL argument.
*
* Adding an empty component results in no effect (i.e., the separator
* char is not doubled).
*
* If EXTENSION is non-null, it will be appended to the final string
* without a separator character.
*/
static const char *
v_extend_with_adm_name (const char *path,
const char *extension,
svn_boolean_t use_tmp,
apr_pool_t *pool,
va_list ap)
{
const char *this;
/* Tack on the administrative subdirectory. */
path = svn_path_join (path, SVN_WC_ADM_DIR_NAME, pool);
/* If this is a tmp file, name it into the tmp area. */
if (use_tmp)
path = svn_path_join (path, SVN_WC__ADM_TMP, pool);
/* Tack on everything else. */
while ((this = va_arg (ap, const char *)) != NULL)
{
if (this[0] == '\0')
continue;
path = svn_path_join (path, this, pool);
}
if (extension)
path = apr_pstrcat (pool, path, extension, NULL);
return path;
}
/* See v_extend_with_adm_name() for details. */
static const char *
extend_with_adm_name (const char *path,
const char *extension,
svn_boolean_t use_tmp,
apr_pool_t *pool,
...)
{
va_list ap;
va_start (ap, pool);
path = v_extend_with_adm_name (path, extension, use_tmp, pool, ap);
va_end (ap);
return path;
}
const char *
svn_wc__adm_path (const char *path,
svn_boolean_t tmp,
apr_pool_t *pool,
...)
{
va_list ap;
va_start (ap, pool);
path = v_extend_with_adm_name (path, NULL, tmp, pool, ap);
va_end (ap);
return path;
}
svn_boolean_t
svn_wc__adm_path_exists (const char *path,
svn_boolean_t tmp,
apr_pool_t *pool,
...)
{
svn_node_kind_t kind;
svn_error_t *err;
va_list ap;
va_start (ap, pool);
path = v_extend_with_adm_name (path, NULL, tmp, pool, ap);
va_end (ap);
err = svn_io_check_path (path, &kind, pool);
if (err)
svn_error_clear (err);
if (kind == svn_node_none)
return FALSE;
else
return TRUE;
}
/*** Making and using files in the adm area. ***/
/* Create an empty THING in the adm area with permissions set to PERMS.
* If TMP is non-zero, then create THING in the tmp dir.
*
* Does not check if THING already exists, so be careful -- THING will
* be empty after this no matter what.
*/
svn_error_t *
svn_wc__make_adm_thing (svn_wc_adm_access_t *adm_access,
const char *thing,
svn_node_kind_t type,
apr_fileperms_t perms,
svn_boolean_t tmp,
apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
apr_file_t *f = NULL;
const char *path;
SVN_ERR (svn_wc__adm_write_check (adm_access));
path = extend_with_adm_name (svn_wc_adm_access_path (adm_access),
NULL, tmp, pool, thing, NULL);
if (type == svn_node_file)
{
SVN_ERR (svn_io_file_open (&f, path,
(APR_WRITE | APR_CREATE | APR_EXCL),
perms,
pool));
/* Creation succeeded, so close immediately. */
SVN_ERR (svn_io_file_close (f, pool));
}
else if (type == svn_node_dir)
{
SVN_ERR (svn_io_dir_make (path, perms, pool));
}
else /* unknown type argument, wrongness */
{
/* We're only capturing this here because there wouldn't be a
segfault or other obvious indicator that something went
wrong. Even so, not sure if it's appropriate. Thoughts? */
err = svn_error_create
(0, NULL, _("Bad type indicator"));
}
return err;
}
/*** Syncing files in the adm area. ***/
static svn_error_t *
sync_adm_file (const char *path,
const char *extension,
apr_pool_t *pool,
...)
{
/* Some code duplication with close_adm_file() seems unavoidable,
given how C va_lists work. */
const char *tmp_path;
va_list ap;
/* Extend tmp name. */
va_start (ap, pool);
tmp_path = v_extend_with_adm_name (path, extension, 1, pool, ap);
va_end (ap);
/* Extend real name. */
va_start (ap, pool);
path = v_extend_with_adm_name (path, extension, 0, pool, ap);
va_end (ap);
/* Rename. */
SVN_ERR (svn_wc__prep_file_for_replacement (path, TRUE, pool));
SVN_ERR (svn_io_file_rename (tmp_path, path, pool));
SVN_ERR (svn_io_set_file_read_only (path, FALSE, pool));
return SVN_NO_ERROR;
}
/* Rename a tmp text-base file to its real text-base name.
The file had better already be closed. */
svn_error_t *
svn_wc__sync_text_base (const char *path, apr_pool_t *pool)
{
const char *parent_path, *base_name;
svn_path_split (path, &parent_path, &base_name, pool);
return sync_adm_file (parent_path,
SVN_WC__BASE_EXT,
pool,
SVN_WC__ADM_TEXT_BASE,
base_name,
NULL);
}
const char *
svn_wc__text_base_path (const char *path,
svn_boolean_t tmp,
apr_pool_t *pool)
{
const char *newpath, *base_name;
svn_path_split (path, &newpath, &base_name, pool);
return extend_with_adm_name (newpath,
SVN_WC__BASE_EXT,
tmp,
pool,
SVN_WC__ADM_TEXT_BASE,
base_name,
NULL);
}
static svn_error_t *
prop_path_internal (const char **prop_path,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t base,
svn_boolean_t wcprop,
svn_boolean_t tmp,
apr_pool_t *pool)
{
const svn_wc_entry_t *entry;
const char *entry_name;
SVN_ERR (svn_wc_entry (&entry, path, adm_access, FALSE, pool));
if (entry && entry->kind == svn_node_dir) /* It's a working copy dir */
{
*prop_path = extend_with_adm_name
(path,
NULL,
tmp,
pool,
base ? SVN_WC__ADM_DIR_PROP_BASE
: (wcprop ? SVN_WC__ADM_DIR_WCPROPS : SVN_WC__ADM_DIR_PROPS),
NULL);
}
else /* It's either a file, or a non-wc dir (i.e., maybe an ex-file) */
{
int wc_format = svn_wc__adm_wc_format (adm_access);
svn_path_split (path, prop_path, &entry_name, pool);
if (wc_format <= SVN_WC__OLD_PROPNAMES_VERSION)
{
*prop_path = extend_with_adm_name
(*prop_path,
base ? SVN_WC__BASE_EXT : NULL,
tmp,
pool,
base ? SVN_WC__ADM_PROP_BASE
: (wcprop ? SVN_WC__ADM_WCPROPS : SVN_WC__ADM_PROPS),
entry_name,
NULL);
}
else
{
*prop_path = extend_with_adm_name
(*prop_path,
base ? SVN_WC__BASE_EXT : SVN_WC__WORK_EXT,
tmp,
pool,
base ? SVN_WC__ADM_PROP_BASE
: (wcprop ? SVN_WC__ADM_WCPROPS : SVN_WC__ADM_PROPS),
entry_name,
NULL);
}
}
return SVN_NO_ERROR;
}
/* Return a path to the 'wcprop' file for PATH, possibly in TMP area. */
svn_error_t *
svn_wc__wcprop_path (const char **wcprop_path,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t tmp,
apr_pool_t *pool)
{
return prop_path_internal (wcprop_path, path, adm_access, FALSE, TRUE, tmp,
pool);
}
svn_error_t *
svn_wc__prop_path (const char **prop_path,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t tmp,
apr_pool_t *pool)
{
return prop_path_internal (prop_path, path, adm_access, FALSE, FALSE, tmp,
pool);
}
svn_error_t *
svn_wc__prop_base_path (const char **prop_path,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t tmp,
apr_pool_t *pool)
{
return prop_path_internal (prop_path, path, adm_access, TRUE, FALSE, tmp,
pool);
}
/*** Opening and closing files in the adm area. ***/
/* Open a file somewhere in the adm area for directory PATH.
* First, add the adm subdir as the next component of PATH, then add
* each of the varargs (they are char *'s), then add EXTENSION if it
* is non-null, then open the resulting file as *HANDLE.
*
* If FLAGS indicates writing, open the file in the adm tmp area.
* This means the file will probably need to be renamed from there,
* either by passing the sync flag to close_adm_file() later, or with
* an explicit call to sync_adm_file().
*/
static svn_error_t *
open_adm_file (apr_file_t **handle,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -