📄 io.c
字号:
const char *native_path;
SVN_ERR (svn_path_cstring_from_utf8 (&native_path, path, pool));
status = apr_file_mtime_set (native_path, apr_time, pool);
if (status)
return svn_error_wrap_apr
(status, "Can't set access time of '%s'", path);
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[BUFSIZ]; /* What's a good size for a read chunk? */
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 = sizeof (buf);
err = svn_io_file_read (f, buf, &len, pool);
while (! err)
{
apr_md5_update (&context, buf, len);
len = sizeof (buf);
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. ***/
svn_error_t *
svn_io_set_file_read_only (const char *path,
svn_boolean_t ignore_enoent,
apr_pool_t *pool)
{
apr_status_t status;
const char *path_apr;
SVN_ERR (svn_path_cstring_from_utf8 (&path_apr, path, pool));
status = apr_file_attrs_set (path_apr,
APR_FILE_ATTR_READONLY,
APR_FILE_ATTR_READONLY,
pool);
if (status && status != APR_ENOTIMPL)
if (!ignore_enoent || !APR_STATUS_IS_ENOENT(status))
return svn_error_wrap_apr (status,
"Can't set file '%s' read-only", path);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_set_file_read_write (const char *path,
svn_boolean_t ignore_enoent,
apr_pool_t *pool)
{
apr_status_t status;
const char *path_apr;
SVN_ERR (svn_path_cstring_from_utf8 (&path_apr, path, pool));
status = apr_file_attrs_set (path_apr,
0,
APR_FILE_ATTR_READONLY,
pool);
if (status && status != APR_ENOTIMPL)
if (!ignore_enoent || !APR_STATUS_IS_ENOENT(status))
return svn_error_wrap_apr (status,
"Can't set file '%s' read-write", path);
return SVN_NO_ERROR;
}
/* 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)
{
apr_file_t *fp;
const char *unique_name;
SVN_ERR (svn_io_open_unique_file (&fp, &unique_name, path_apr,
".tmp", FALSE, pool));
SVN_ERR (svn_io_file_close (fp, 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;
}
svn_error_t *
svn_io_set_file_executable (const char *path,
svn_boolean_t executable,
svn_boolean_t ignore_enoent,
apr_pool_t *pool)
{
apr_status_t status;
const char *path_apr;
SVN_ERR (svn_path_cstring_from_utf8 (&path_apr, path, pool));
if (executable)
{
apr_finfo_t finfo;
apr_fileperms_t perms_to_set;
/* Try to change only a minimal amount of the perms first
by getting the current perms and adding execute bits
only on where read perms are granted. If this fails
fall through to the apr_file_perms_set() call. */
status = apr_stat (&finfo, path_apr, APR_FINFO_PROT, pool);
if (status)
{
if (ignore_enoent && APR_STATUS_IS_ENOENT (status))
return SVN_NO_ERROR;
else if (status != APR_ENOTIMPL)
return svn_error_wrap_apr (status,
"Can't change executability of "
"file '%s'", path);
}
else
{
perms_to_set = finfo.protection;
if (finfo.protection & APR_UREAD)
perms_to_set |= APR_UEXECUTE;
if (finfo.protection & APR_GREAD)
perms_to_set |= APR_GEXECUTE;
if (finfo.protection & APR_WREAD)
perms_to_set |= APR_WEXECUTE;
/* If we aren't changing anything then just return, this save
some system calls and helps with shared working copies */
if (perms_to_set == finfo.protection)
return SVN_NO_ERROR;
status = apr_file_perms_set (path_apr, perms_to_set);
if (status)
{
if (APR_STATUS_IS_EPERM (status))
{
/* We don't have permissions to change the
permissions! Try a move, copy, and delete
workaround to see if we can get the file owned by
us. If these succeed, try the permissions set
again.
Note that we only attempt this in the
stat-available path. This assumes that the
move-copy workaround will only be helpful on
platforms that implement apr_stat. */
SVN_ERR (reown_file (path_apr, pool));
status = apr_file_perms_set (path_apr, perms_to_set);
}
if (status)
{
if (ignore_enoent && APR_STATUS_IS_ENOENT (status))
return SVN_NO_ERROR;
else if (status != APR_ENOTIMPL)
return svn_error_wrap_apr (status,
"Can't change executability of "
"file '%s'", path);
}
else
return SVN_NO_ERROR;
}
else
return SVN_NO_ERROR;
}
status = apr_file_attrs_set (path_apr,
APR_FILE_ATTR_EXECUTABLE,
APR_FILE_ATTR_EXECUTABLE,
pool);
}
else
status = apr_file_attrs_set (path_apr,
0,
APR_FILE_ATTR_EXECUTABLE,
pool);
if (status && status != APR_ENOTIMPL)
if (!ignore_enoent || !APR_STATUS_IS_ENOENT(status))
return svn_error_wrap_apr (status,
"Can't change executability of file '%s'",
path);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_is_file_executable(svn_boolean_t *executable,
const char *path,
apr_pool_t *pool)
{
#if defined(APR_HAS_USER) && !defined(WIN32)
apr_finfo_t file_info;
apr_status_t apr_err;
apr_uid_t uid;
apr_gid_t gid;
*executable = FALSE;
/* Get file and user info. */
SVN_ERR (svn_io_stat (&file_info, path,
(APR_FINFO_PROT | APR_FINFO_OWNER),
pool));
apr_err = apr_uid_current (&uid, &gid, pool);
if (apr_err)
return svn_error_wrap_apr(apr_err, "Error getting UID of process");
/* Check executable bit for current user. */
if (apr_uid_compare(uid, file_info.user) == APR_SUCCESS)
*executable = (file_info.protection & APR_UEXECUTE);
else if (apr_gid_compare(gid, file_info.group) == APR_SUCCESS)
*executable = (file_info.protection & APR_GEXECUTE);
else
*executable = (file_info.protection & APR_WEXECUTE);
#else /* defined(WIN32) || !defined(APR_HAS_USER) */
*executable = FALSE;
#endif
return SVN_NO_ERROR;
}
/*** File locking. ***/
/* Clear all outstanding locks on ARG, an open apr_file_t *. */
static apr_status_t
svn_io__file_clear_and_close (void *arg)
{
apr_status_t apr_err;
apr_file_t *f = arg;
/* Remove locks. */
apr_err = apr_file_unlock (f);
if (apr_err)
return apr_err;
/* Close the file. */
apr_err = apr_file_close (f);
if (apr_err)
return apr_err;
return 0;
}
svn_error_t *svn_io_file_lock (const char *lock_file,
svn_boolean_t exclusive,
apr_pool_t *pool)
{
return svn_io_file_lock2(lock_file, exclusive, FALSE, pool);
}
svn_error_t *svn_io_file_lock2 (const char *lock_file,
svn_boolean_t exclusive,
svn_boolean_t nonblocking,
apr_pool_t *pool)
{
int locktype = APR_FLOCK_SHARED;
apr_file_t *lockfile_handle;
apr_int32_t flags;
apr_status_t apr_err;
if(exclusive == TRUE)
locktype = APR_FLOCK_EXCLUSIVE;
flags = APR_READ;
if (locktype == APR_FLOCK_EXCLUSIVE)
flags |= APR_WRITE;
if (nonblocking == TRUE)
locktype |= APR_FLOCK_NONBLOCK;
SVN_ERR (svn_io_file_open (&lockfile_handle, lock_file, flags,
APR_OS_DEFAULT,
pool));
/* Get lock on the filehandle. */
apr_err = apr_file_lock (lockfile_handle, locktype);
if (apr_err)
{
const char *lockname = "unknown";
if (locktype == APR_FLOCK_SHARED)
lockname = "shared";
if (locktype == APR_FLOCK_EXCLUSIVE)
lockname = "exclusive";
return svn_error_wrap_apr
(apr_err, "Can't get %s lock on file '%s'", lockname, lock_file);
}
apr_pool_cleanup_register (pool, lockfile_handle,
svn_io__file_clear_and_close,
apr_pool_cleanup_null);
return SVN_NO_ERROR;
}
/* Data consistency/coherency operations. */
static svn_error_t *
do_io_file_wrapper_cleanup (apr_file_t *file, apr_status_t status,
const char *op, apr_pool_t *pool);
svn_error_t *svn_io_file_flush_to_disk (apr_file_t *file,
apr_pool_t *pool)
{
apr_os_file_t filehand;
/* First make sure that any user-space buffered data is flushed. */
SVN_ERR (do_io_file_wrapper_cleanup (file, apr_file_flush (file),
"flush", pool));
apr_os_file_get (&filehand, file);
/* Call the operating system specific function to actually force the
data to disk. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -