📄 io.c
字号:
/* Try to open a temporary file in the temporary dir, write to it,
and then close it. */
static int test_tempdir(const char *temp_dir, apr_pool_t *p)
{
apr_file_t *dummy_file;
const char *path = apr_pstrcat(p, temp_dir, "/apr-tmp.XXXXXX", NULL);
if (apr_file_mktemp(&dummy_file, (char *)path, 0, p) == APR_SUCCESS) {
if (apr_file_putc('!', dummy_file) == APR_SUCCESS) {
if (apr_file_close(dummy_file) == APR_SUCCESS) {
return 1;
}
}
}
return 0;
}
#endif
svn_error_t *
svn_io_temp_dir (const char **dir,
apr_pool_t *pool)
{
#if 1 /* TODO: Remove this code when APR 0.9.6 is released. */
apr_status_t apr_err;
static const char *try_dirs[] = { "/tmp", "/usr/tmp", "/var/tmp" };
static const char *try_envs[] = { "TMP", "TEMP", "TMPDIR" };
const char *temp_dir;
char *cwd;
apr_size_t i;
/* Our goal is to find a temporary directory suitable for writing
into. We'll only pay the price once if we're successful -- we
cache our successful find. Here's the order in which we'll try
various paths:
$TMP
$TEMP
$TMPDIR
"C:\TEMP" (windows only)
"/tmp"
"/var/tmp"
"/usr/tmp"
`pwd`
NOTE: This algorithm is basically the same one used by Python
2.2's tempfile.py module. */
/* Try the environment first. */
for (i = 0; i < (sizeof(try_envs) / sizeof(const char *)); i++)
{
char *value;
apr_err = apr_env_get(&value, try_envs[i], pool);
if ((apr_err == APR_SUCCESS) && value)
{
apr_size_t len = strlen(value);
if (len && (len < APR_PATH_MAX) && test_tempdir(value, pool))
{
temp_dir = value;
goto end;
}
}
}
#ifdef WIN32
/* Next, on Win32, try the C:\TEMP directory. */
if (test_tempdir("C:\\TEMP", pool))
{
temp_dir = "C:\\TEMP";
goto end;
}
#endif /* WIN32 */
/* Next, try a set of hard-coded paths. */
for (i = 0; i < (sizeof(try_dirs) / sizeof(const char *)); i++)
{
if (test_tempdir(try_dirs[i], pool))
{
temp_dir = try_dirs[i];
goto end;
}
}
/* Finally, try the current working directory. */
if (APR_SUCCESS == apr_filepath_get(&cwd, APR_FILEPATH_NATIVE, pool))
{
if (test_tempdir(cwd, pool))
{
temp_dir = cwd;
goto end;
}
}
return svn_error_create
(APR_EGENERAL, NULL, "Can't find a temporary directory");
end:
*dir = svn_path_canonicalize(temp_dir, pool);
return SVN_NO_ERROR;
#else
apr_status_t apr_err = apr_temp_dir_get (dir, pool);
if (apr_err)
return svn_error_wrap_apr (apr_err, "Can't find a temporary directory");
*dir = svn_path_canonicalize (*dir, pool);
return SVN_NO_ERROR;
#endif
}
/*** Creating, copying and appending files. ***/
svn_error_t *
svn_io_copy_file (const char *src,
const char *dst,
svn_boolean_t copy_perms,
apr_pool_t *pool)
{
apr_file_t *d;
apr_status_t apr_err;
const char *src_apr, *dst_tmp_apr;
const char *dst_tmp;
SVN_ERR (svn_path_cstring_from_utf8 (&src_apr, src, pool));
/* For atomicity, we translate to a tmp file and then rename the tmp
file over the real destination. */
SVN_ERR (svn_io_open_unique_file (&d, &dst_tmp, dst, ".tmp", FALSE, pool));
SVN_ERR (svn_path_cstring_from_utf8 (&dst_tmp_apr, dst_tmp, pool));
SVN_ERR (svn_io_file_close (d, pool));
apr_err = apr_file_copy (src_apr, dst_tmp_apr, APR_OS_DEFAULT, pool);
if (apr_err)
return svn_error_wrap_apr
(apr_err, "Can't copy '%s' to '%s'", src, dst_tmp);
/* If copying perms, set the perms on dst_tmp now, so they will be
atomically inherited in the upcoming rename. But note that we
had to wait until now to set perms, because if they say
read-only, then we'd have failed filling dst_tmp's contents. */
/* ### FIXME: apr_file_copy with perms may fail on Win32. We need a
platform-specific implementation to get the permissions right. */
#ifndef WIN32
if (copy_perms)
{
apr_file_t *s;
apr_finfo_t finfo;
SVN_ERR (svn_io_file_open (&s, src, APR_READ, APR_OS_DEFAULT, pool));
SVN_ERR (svn_io_file_info_get (&finfo, APR_FINFO_PROT, s, pool));
SVN_ERR (svn_io_file_close (s, pool));
apr_err = apr_file_perms_set (dst_tmp_apr, finfo.protection);
/* We shouldn't be able to get APR_INCOMPLETE or APR_ENOTIMPL
here under normal circumstances, because the perms themselves
came from a call to apr_file_info_get(), and we already know
this is the non-Win32 case. But if it does happen, it's not
an error. */
if ((apr_err != APR_SUCCESS)
&& (apr_err != APR_INCOMPLETE)
&& (apr_err != APR_ENOTIMPL))
{
return svn_error_wrap_apr
(apr_err, "Can't set permissions on '%s'", dst_tmp);
}
}
#endif /* ! WIN32 */
return svn_io_file_rename (dst_tmp, dst, pool);
}
svn_error_t *
svn_io_append_file (const char *src, const char *dst, apr_pool_t *pool)
{
apr_status_t apr_err;
const char *src_apr, *dst_apr;
SVN_ERR (svn_path_cstring_from_utf8 (&src_apr, src, pool));
SVN_ERR (svn_path_cstring_from_utf8 (&dst_apr, dst, pool));
apr_err = apr_file_append (src_apr, dst_apr, APR_OS_DEFAULT, pool);
if (apr_err)
return svn_error_wrap_apr (apr_err, "Can't append '%s' to '%s'", src, dst);
return SVN_NO_ERROR;
}
svn_error_t *svn_io_copy_dir_recursively (const char *src,
const char *dst_parent,
const char *dst_basename,
svn_boolean_t copy_perms,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
svn_node_kind_t kind;
apr_status_t status;
const char *dst_path;
apr_dir_t *this_dir;
apr_finfo_t this_entry;
apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
/* Make a subpool for recursion */
apr_pool_t *subpool = svn_pool_create (pool);
/* The 'dst_path' is simply dst_parent/dst_basename */
dst_path = svn_path_join (dst_parent, dst_basename, pool);
/* Sanity checks: SRC and DST_PARENT are directories, and
DST_BASENAME doesn't already exist in DST_PARENT. */
SVN_ERR (svn_io_check_path (src, &kind, subpool));
if (kind != svn_node_dir)
return svn_error_createf (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
"Source '%s' is not a directory",
src);
SVN_ERR (svn_io_check_path (dst_parent, &kind, subpool));
if (kind != svn_node_dir)
return svn_error_createf (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
"Destination '%s' is not a directory",
dst_parent);
SVN_ERR (svn_io_check_path (dst_path, &kind, subpool));
if (kind != svn_node_none)
return svn_error_createf (SVN_ERR_ENTRY_EXISTS, NULL,
"Destination '%s' already exists",
dst_path);
/* Create the new directory. */
/* ### TODO: copy permissions? */
SVN_ERR (svn_io_dir_make (dst_path, APR_OS_DEFAULT, pool));
/* Loop over the dirents in SRC. ('.' and '..' are auto-excluded) */
SVN_ERR (svn_io_dir_open (&this_dir, src, subpool));
for (status = apr_dir_read (&this_entry, flags, this_dir);
status == APR_SUCCESS;
status = apr_dir_read (&this_entry, flags, this_dir))
{
if ((this_entry.name[0] == '.')
&& ((this_entry.name[1] == '\0')
|| ((this_entry.name[1] == '.')
&& (this_entry.name[2] == '\0'))))
{
continue;
}
else
{
const char *src_target, *entryname_utf8;
if (cancel_func)
SVN_ERR (cancel_func (cancel_baton));
SVN_ERR (svn_path_cstring_to_utf8 (&entryname_utf8,
this_entry.name, subpool));
src_target = svn_path_join (src, entryname_utf8, subpool);
if (this_entry.filetype == APR_REG) /* regular file */
{
const char *dst_target = svn_path_join (dst_path, entryname_utf8,
subpool);
SVN_ERR (svn_io_copy_file (src_target, dst_target,
copy_perms, subpool));
}
else if (this_entry.filetype == APR_LNK) /* symlink */
{
const char *dst_target = svn_path_join (dst_path, entryname_utf8,
subpool);
SVN_ERR (svn_io_copy_link (src_target, dst_target,
subpool));
}
else if (this_entry.filetype == APR_DIR) /* recurse */
{
SVN_ERR (svn_io_copy_dir_recursively
(src_target,
dst_path,
entryname_utf8,
copy_perms,
cancel_func,
cancel_baton,
subpool));
}
/* ### support other APR node types someday?? */
}
}
if (! (APR_STATUS_IS_ENOENT (status)))
return svn_error_wrap_apr (status, "Can't read directory '%s'", src);
status = apr_dir_close (this_dir);
if (status)
return svn_error_wrap_apr (status, "Error closing directory '%s'", src);
/* Free any memory used by recursion */
apr_pool_destroy (subpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_make_dir_recursively (const char *path, apr_pool_t *pool)
{
svn_error_t *err;
char *dir;
if (svn_path_is_empty (path))
/* Empty path (current dir) is assumed to always exist,
so we do nothing, per docs. */
return SVN_NO_ERROR;
#if 0
/* ### Use this implementation if/when apr_dir_make_recursive is
available on all platforms, not just on Unix. --xbc */
apr_err = apr_dir_make_recursive (path_apr, APR_OS_DEFAULT, pool);
if (apr_err)
return svn_error_wrap_apr (apr_err, "Can't make directory '%s'", path);
return SVN_NO_ERROR;
#else
/* Try to make PATH right out */
err = svn_io_dir_make (path, APR_OS_DEFAULT, pool);
if (! err || APR_STATUS_IS_EEXIST (err->apr_err))
{
/* We succeeded, or path already exists; either way we're done. */
svn_error_clear (err);
return SVN_NO_ERROR;
}
else if (APR_STATUS_IS_ENOENT (err->apr_err))
{
/* Missing an intermediate dir. */
dir = svn_path_dirname (path, pool);
SVN_ERR (svn_io_make_dir_recursively (dir, pool));
return svn_io_dir_make (path, APR_OS_DEFAULT, pool);
}
else
return err;
#endif
}
svn_error_t *svn_io_file_create (const char *file,
const char *contents,
apr_pool_t *pool)
{
apr_file_t *f;
apr_size_t written;
SVN_ERR (svn_io_file_open (&f, file,
(APR_WRITE | APR_CREATE | APR_EXCL),
APR_OS_DEFAULT,
pool));
SVN_ERR (svn_io_file_write_full (f, contents, strlen (contents),
&written, pool));
SVN_ERR (svn_io_file_close (f, pool));
return SVN_NO_ERROR;
}
svn_error_t *svn_io_dir_file_copy (const char *src_path,
const char *dest_path,
const char *file,
apr_pool_t *pool)
{
const char *file_dest_path = svn_path_join (dest_path, file, pool);
const char *file_src_path = svn_path_join (src_path, file, pool);
SVN_ERR (svn_io_copy_file (file_src_path, file_dest_path, TRUE, pool));
return SVN_NO_ERROR;
}
/*** Modtime checking. ***/
svn_error_t *
svn_io_file_affected_time (apr_time_t *apr_time,
const char *path,
apr_pool_t *pool)
{
apr_finfo_t finfo;
SVN_ERR (svn_io_stat (&finfo, path, APR_FINFO_MIN | APR_FINFO_LINK, pool));
*apr_time = finfo.mtime;
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_set_file_affected_time (apr_time_t apr_time,
const char *path,
apr_pool_t *pool)
{
apr_status_t status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -