📄 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-2006 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_file_io.h>#include <apr_strings.h>#include "svn_types.h"#include "svn_error.h"#include "svn_io.h"#include "svn_path.h"#include "svn_wc.h"#include "wc.h"#include "adm_files.h"#include "entries.h"#include "lock.h"#include "svn_private_config.h"/*** File names in the adm area. ***//* The default name of the WC admin directory. This name is always checked by svn_wc_is_adm_dir. */static const char default_adm_dir_name[] = ".svn";/* The name that is actually used for the WC admin directory. The commonest case where this won't be the default is in Windows ASP.NET development environments, which choke on ".svn". */static const char *adm_dir_name = default_adm_dir_name;svn_boolean_tsvn_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){ /* This is the canonical list of administrative directory names. FIXME: An identical list is used in libsvn_subr/opt.c:svn_opt_args_to_target_array2(), but that function can't use this list, because that use would create a circular dependency between libsvn_wc and libsvn_subr. Make sure changes to the lists are always synchronized! */ 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)) { /* Use the pointer to the statically allocated string constant, to avoid potential pool lifetime issues. */ 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_path_local_style(name, pool));}/* 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, 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_tsvn_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); /* Return early, since kind is undefined in this case. */ return FALSE; } 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_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);}const char *svn_wc__text_revert_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__REVERT_EXT, tmp, pool, SVN_WC__ADM_TEXT_BASE, base_name, NULL);}/* Kind for prop_path_internal. */typedef enum prop_path_kind_t{ prop_path_kind_base = 0, prop_path_kind_revert, prop_path_kind_wcprop, prop_path_kind_working} prop_path_kind_t;static svn_error_t *prop_path_internal(const char **prop_path, const char *path, svn_node_kind_t kind, prop_path_kind_t path_kind, svn_boolean_t tmp, apr_pool_t *pool){ if (kind == svn_node_dir) /* It's a working copy dir */ { static const char * names[] = { SVN_WC__ADM_DIR_PROP_BASE, /* prop_path_kind_base */ SVN_WC__ADM_DIR_PROP_REVERT, /* prop_path_kind_revert */ SVN_WC__ADM_DIR_WCPROPS, /* prop_path_kind_wcprop */ SVN_WC__ADM_DIR_PROPS /* prop_path_kind_working */ }; *prop_path = extend_with_adm_name (path, NULL, tmp, pool, names[path_kind], NULL); } else /* It's a file */ { static const char * extensions[] = { SVN_WC__BASE_EXT, /* prop_path_kind_base */ SVN_WC__REVERT_EXT, /* prop_path_kind_revert */ SVN_WC__WORK_EXT, /* prop_path_kind_wcprop */ SVN_WC__WORK_EXT /* prop_path_kind_working */ }; static const char * dirs[] = { SVN_WC__ADM_PROP_BASE, /* prop_path_kind_base */ SVN_WC__ADM_PROP_BASE, /* prop_path_kind_revert */ SVN_WC__ADM_WCPROPS, /* prop_path_kind_wcprop */ SVN_WC__ADM_PROPS /* prop_path_kind_working */ }; const char *base_name; svn_path_split(path, prop_path, &base_name, pool); *prop_path = extend_with_adm_name (*prop_path, extensions[path_kind], tmp, pool, dirs[path_kind], base_name,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -