📄 io.c
字号:
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"), svn_path_local_style(src, pool)); 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"), svn_path_local_style(dst_parent, pool)); 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"), svn_path_local_style(dst_path, pool)); /* Create the new directory. */ /* ### TODO: copy permissions (needs apr_file_attrs_get()) */ 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 */ { /* Prevent infinite recursion by filtering off our newly created destination path. */ if (strcmp(src, dst_parent) == 0 && strcmp(entryname_utf8, dst_basename) == 0) continue; 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'"), svn_path_local_style(src, pool)); status = apr_dir_close(this_dir); if (status) return svn_error_wrap_apr(status, _("Error closing directory '%s'"), svn_path_local_style(src, pool)); /* 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){ const char *path_apr; apr_status_t apr_err; 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; SVN_ERR(svn_path_cstring_from_utf8(&path_apr, path, pool)); 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'"), svn_path_local_style(path, pool)); return SVN_NO_ERROR;}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; const char *native_path;#ifdef AS400 apr_utimbuf_t aubuf; apr_finfo_t finfo;#endif SVN_ERR(svn_path_cstring_from_utf8(&native_path, path, pool));#ifndef AS400 status = apr_file_mtime_set(native_path, apr_time, pool);#else /* apr_file_mtime_set() isn't implemented on OS400, but IBM does provide * the OS400 specific function apr_utime() which can be used instead. */ /* Get the file's current access time, we don't want to change that, * just the mod time. */ status = apr_stat(&finfo, native_path, APR_FINFO_ATIME, pool); if (!status) { aubuf.atime = finfo.atime; aubuf.mtime = apr_time; status = apr_utime(native_path, &aubuf); }#endif if (status) return svn_error_wrap_apr (status, _("Can't set access time of '%s'"), svn_path_local_style(path, pool)); return SVN_NO_ERROR;}svn_error_t *svn_io_filesizes_different_p(svn_boolean_t *different_p, const char *file1, const char *file2, apr_pool_t *pool){ apr_finfo_t finfo1; apr_finfo_t finfo2; apr_status_t status; const char *file1_apr, *file2_apr; /* Not using svn_io_stat() because don't want to generate svn_error_t objects for non-error conditions. */ SVN_ERR(svn_path_cstring_from_utf8(&file1_apr, file1, pool)); SVN_ERR(svn_path_cstring_from_utf8(&file2_apr, file2, pool)); /* Stat both files */ status = apr_stat(&finfo1, file1_apr, APR_FINFO_MIN, pool); if (status) { /* If we got an error stat'ing a file, it could be because the file was removed... or who knows. Whatever the case, we don't know if the filesizes are definitely different, so assume that they're not. */ *different_p = FALSE; return SVN_NO_ERROR; } status = apr_stat(&finfo2, file2_apr, APR_FINFO_MIN, pool); if (status) { /* See previous comment. */ *different_p = FALSE; return SVN_NO_ERROR; } /* Examine file sizes */ if (finfo1.size == finfo2.size) *different_p = FALSE; else *different_p = TRUE; return SVN_NO_ERROR;}svn_error_t *svn_io_file_checksum(unsigned char digest[], const char *file, apr_pool_t *pool){ struct apr_md5_ctx_t context; apr_file_t *f = NULL; svn_error_t *err; char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); apr_size_t len; /* ### The apr_md5 functions return apr_status_t, but they only return success, and really, what could go wrong? So below, we ignore their return values. */ apr_md5_init(&context); SVN_ERR(svn_io_file_open(&f, file, APR_READ, APR_OS_DEFAULT, pool)); len = SVN__STREAM_CHUNK_SIZE; err = svn_io_file_read(f, buf, &len, pool); while (! err) { apr_md5_update(&context, buf, len); len = SVN__STREAM_CHUNK_SIZE; err = svn_io_file_read(f, buf, &len, pool); }; if (err && ! APR_STATUS_IS_EOF(err->apr_err)) return err; svn_error_clear(err); SVN_ERR(svn_io_file_close(f, pool)); apr_md5_final(digest, &context); return SVN_NO_ERROR;}/*** Permissions and modes. ***/#ifndef WIN32/* Given the file specified by PATH_APR, attempt to create an identical version of it owned by the current user. This is done by moving it to a temporary location, copying the file back to its old path, then deleting the temporarily moved version. All temporary allocations are done in POOL. */static svn_error_t *reown_file(const char *path_apr, apr_pool_t *pool){ const char *unique_name; SVN_ERR(svn_io_open_unique_file2(NULL, &unique_name, path_apr, ".tmp", svn_io_file_del_none, pool)); SVN_ERR(svn_io_file_rename(path_apr, unique_name, pool)); SVN_ERR(svn_io_copy_file(unique_name, path_apr, TRUE, pool)); SVN_ERR(svn_io_remove_file(unique_name, pool)); return SVN_NO_ERROR;}/* Determine what the read-write PERMS for PATH should be by ORing together the permissions of PATH and the permissions of a temporary file that we create. Unfortunately, this is the only way to determine which combination of write bits (User/Group/World) should be set to restore a file from read-only to read-write. Make temporary allocations in POOL. */static svn_error_t *get_default_file_perms(const char *path, apr_fileperms_t *perms, apr_pool_t *pool){ apr_status_t status; apr_finfo_t tmp_finfo, finfo; apr_file_t *fd; const char *tmp_path; const char *apr_path; /* Get the perms for a newly created file to find out what write * bits should be set. */ SVN_ERR(svn_io_open_unique_file2(&fd, &tmp_path, path, ".tmp", svn_io_file_del_on_close, pool)); status = apr_stat(&tmp_finfo, tmp_path, APR_FINFO_PROT, pool); if (status) return svn_error_wrap_apr(status, _("Can't get default file perms " "for file at '%s' (file stat error)"), path); apr_file_close(fd); /* Get the perms for the original file so we'll have any other bits * that were already set (like the execute bits, for example). */ SVN_ERR(svn_path_cstring_from_utf8(&apr_path, path, pool)); status = apr_file_open(&fd, apr_path, APR_READ | APR_BINARY, APR_OS_DEFAULT, pool); if (status) return svn_error_wrap_apr(status, _("Can't open file at '%s'"), path); status = apr_stat(&finfo, apr_path, APR_FINFO_PROT, pool); if (status) return svn_error_wrap_apr(status, _("Can't get file perms for file at " "'%s' (file stat error)"), path); apr_file_close(fd); /* Glom the perms together. */ *perms = tmp_finfo.protection | finfo.protection; return SVN_NO_ERROR;}/* This is a helper function for the svn_io_set_file_read* functions that attempts to honor the users umask when dealing with permission changes. */static svn_error_t *io_set_file_perms(const char *path, svn_boolean_t change_readwrite, svn_boolean_t enable_write, svn_boolean_t change_executable, svn_boolean_t executable, svn_boolean_t ignore_enoent, apr_pool_t *pool){ apr_status_t status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -