📄 io.c
字号:
cmdproc_attr, pool);
if (apr_err)
return svn_error_wrap_apr (apr_err, "Can't start process '%s'", cmd);
/* The Win32 apr_proc_wait doesn't set this... */
exitwhy_val = APR_PROC_EXIT;
/* Wait for the cmd command to finish. */
apr_err = apr_proc_wait (&cmd_proc, &exitcode_val, &exitwhy_val, APR_WAIT);
if (APR_STATUS_IS_CHILD_NOTDONE (apr_err))
return svn_error_wrap_apr (apr_err, "Error waiting for process '%s'", cmd);
if (exitwhy)
*exitwhy = exitwhy_val;
else if (! APR_PROC_CHECK_EXIT(exitwhy_val))
return svn_error_createf
(SVN_ERR_EXTERNAL_PROGRAM, NULL,
"Process '%s' failed (exitwhy %d)", cmd, exitwhy_val);
if (exitcode)
*exitcode = exitcode_val;
else if (exitcode_val != 0)
return svn_error_createf
(SVN_ERR_EXTERNAL_PROGRAM, NULL,
"Process '%s' returned error exitcode %d", cmd, exitcode_val);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_run_diff (const char *dir,
const char *const *user_args,
int num_user_args,
const char *label1,
const char *label2,
const char *from,
const char *to,
int *pexitcode,
apr_file_t *outfile,
apr_file_t *errfile,
const char *diff_cmd,
apr_pool_t *pool)
{
const char **args;
int i;
int exitcode;
int nargs = 4; /* the diff command itself, two paths, plus a trailing NULL */
const char *diff_utf8;
apr_pool_t *subpool = svn_pool_create (pool);
SVN_ERR (svn_path_cstring_to_utf8 (&diff_utf8, diff_cmd, pool));
if (pexitcode == NULL)
pexitcode = &exitcode;
if (user_args != NULL)
nargs += num_user_args;
else
nargs += 1; /* -u */
if (label1 != NULL)
nargs += 2; /* the -L and the label itself */
if (label2 != NULL)
nargs += 2; /* the -L and the label itself */
args = apr_palloc (subpool, nargs * sizeof(char *));
i = 0;
args[i++] = diff_utf8;
if (user_args != NULL)
{
int j;
for (j = 0; j < num_user_args; ++j)
args[i++] = user_args[j];
}
else
args[i++] = "-u"; /* assume -u if the user didn't give us any args */
if (label1 != NULL)
{
args[i++] = "-L";
args[i++] = label1;
}
if (label2 != NULL)
{
args[i++] = "-L";
args[i++] = label2;
}
args[i++] = svn_path_local_style (from, subpool);
args[i++] = svn_path_local_style (to, subpool);
args[i++] = NULL;
assert (i == nargs);
SVN_ERR (svn_io_run_cmd (dir, diff_utf8, args, pexitcode, NULL, TRUE,
NULL, outfile, errfile, subpool));
/* The man page for (GNU) diff describes the return value as:
"An exit status of 0 means no differences were found, 1 means
some differences were found, and 2 means trouble."
A return value of 2 typically occurs when diff cannot read its input
or write to its output, but in any case we probably ought to return an
error for anything other than 0 or 1 as the output is likely to be
corrupt.
*/
if (*pexitcode != 0 && *pexitcode != 1)
return svn_error_createf (SVN_ERR_EXTERNAL_PROGRAM, NULL,
"'%s' returned %d", diff_utf8, *pexitcode);
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_run_diff3 (const char *dir,
const char *mine,
const char *older,
const char *yours,
const char *mine_label,
const char *older_label,
const char *yours_label,
apr_file_t *merged,
int *exitcode,
const char *diff3_cmd,
apr_pool_t *pool)
{
const char *args[14];
const char *diff3_utf8;
#ifndef NDEBUG
int nargs = 13;
#endif
int i = 0;
SVN_ERR (svn_path_cstring_to_utf8 (&diff3_utf8, diff3_cmd, pool));
/* Labels fall back to sensible defaults if not specified. */
if (mine_label == NULL)
mine_label = ".working";
if (older_label == NULL)
older_label = ".old";
if (yours_label == NULL)
yours_label = ".new";
/* Set up diff3 command line. */
args[i++] = diff3_utf8;
args[i++] = "-E"; /* We tried "-A" here, but that caused
overlapping identical changes to
conflict. See issue #682. */
args[i++] = "-m";
args[i++] = "-L";
args[i++] = mine_label;
args[i++] = "-L";
args[i++] = older_label; /* note: this label is ignored if
using 2-part markers, which is the
case with "-E". */
args[i++] = "-L";
args[i++] = yours_label;
#ifdef SVN_DIFF3_HAS_DIFF_PROGRAM_ARG
{
svn_boolean_t has_arg;
/* ### FIXME: we really shouldn't be reading the config here;
instead, the necessary bits should be passed in by the caller.
But should we add another parameter to this function, when the
whole external diff3 thing might eventually go away? */
apr_hash_t *config;
svn_config_t *cfg;
SVN_ERR (svn_config_get_config (&config, pool));
cfg = config ? apr_hash_get (config, SVN_CONFIG_CATEGORY_CONFIG,
APR_HASH_KEY_STRING) : NULL;
SVN_ERR (svn_config_get_bool (cfg, &has_arg, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_DIFF3_HAS_PROGRAM_ARG,
TRUE));
if (has_arg)
{
const char *diff_cmd, *diff_utf8;
svn_config_get (cfg, &diff_cmd, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_DIFF_CMD, SVN_CLIENT_DIFF);
SVN_ERR (svn_path_cstring_to_utf8 (&diff_utf8, diff_cmd, pool));
args[i++] = apr_pstrcat(pool, "--diff-program=", diff_utf8, NULL);
#ifndef NDEBUG
++nargs;
#endif
}
}
#endif
args[i++] = svn_path_local_style (mine, pool);
args[i++] = svn_path_local_style (older, pool);
args[i++] = svn_path_local_style (yours, pool);
args[i++] = NULL;
assert (i == nargs);
/* Run diff3, output the merged text into the scratch file. */
SVN_ERR (svn_io_run_cmd (dir, diff3_utf8, args,
exitcode, NULL,
TRUE, /* keep environment */
NULL, merged, NULL,
pool));
/* According to the diff3 docs, a '0' means the merge was clean, and
'1' means conflict markers were found. Anything else is real
error. */
if ((*exitcode != 0) && (*exitcode != 1))
return svn_error_createf (SVN_ERR_EXTERNAL_PROGRAM, NULL,
"Error running '%s': exitcode was %d, args were:"
"\nin directory '%s', basenames:\n%s\n%s\n%s",
diff3_utf8, *exitcode,
dir, mine, older, yours);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_detect_mimetype (const char **mimetype,
const char *file,
apr_pool_t *pool)
{
static const char * const generic_binary = "application/octet-stream";
svn_node_kind_t kind;
apr_file_t *fh;
svn_error_t *err;
unsigned char block[1024];
apr_size_t amt_read = sizeof (block);
/* Default return value is NULL. */
*mimetype = NULL;
/* See if this file even exists, and make sure it really is a file. */
SVN_ERR (svn_io_check_path (file, &kind, pool));
if (kind != svn_node_file)
return svn_error_createf (SVN_ERR_BAD_FILENAME, NULL,
"Can't detect MIME type of non-file '%s'",
file);
SVN_ERR (svn_io_file_open (&fh, file, APR_READ, 0, pool));
/* Read a block of data from FILE. */
err = svn_io_file_read (fh, block, &amt_read, pool);
if (err && ! APR_STATUS_IS_EOF(err->apr_err))
return err;
svn_error_clear (err);
/* Now close the file. No use keeping it open any more. */
SVN_ERR (svn_io_file_close (fh, pool));
/* Right now, this function is going to be really stupid. It's
going to examine the first block of data, and make sure that 85%
of the bytes are such that their value is in the ranges 0x07-0x0D
or 0x20-0x7F, and that 100% of those bytes is not 0x00.
If those criteria are not met, we're calling it binary. */
if (amt_read > 0)
{
apr_size_t i;
int binary_count = 0;
/* Run through the data we've read, counting the 'binary-ish'
bytes. HINT: If we see a 0x00 byte, we'll set our count to its
max and stop reading the file. */
for (i = 0; i < amt_read; i++)
{
if (block[i] == 0)
{
binary_count = amt_read;
break;
}
if ((block[i] < 0x07)
|| ((block[i] > 0x0D) && (block[i] < 0x20))
|| (block[i] > 0x7F))
{
binary_count++;
}
}
if (((binary_count * 1000) / amt_read) > 850)
{
*mimetype = generic_binary;
return SVN_NO_ERROR;
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_file_open (apr_file_t **new_file, const char *fname,
apr_int32_t flag, apr_fileperms_t perm,
apr_pool_t *pool)
{
const char *fname_apr;
apr_status_t status;
SVN_ERR (svn_path_cstring_from_utf8 (&fname_apr, fname, pool));
status = apr_file_open (new_file, fname_apr, flag, perm, pool);
if (status)
return svn_error_wrap_apr (status, "Can't open file '%s'", fname);
else
return SVN_NO_ERROR;
}
static svn_error_t *
do_io_file_wrapper_cleanup (apr_file_t *file, apr_status_t status,
const char *op, apr_pool_t *pool)
{
const char *name;
svn_error_t *err;
if (! status)
return SVN_NO_ERROR;
err = file_name_get (&name, file, pool);
name = (! err && name) ? apr_psprintf (pool, "file '%s'", name) : "stream";
svn_error_clear (err);
return svn_error_wrap_apr (status, "Can't %s %s", op, name);
}
svn_error_t *
svn_io_file_close (apr_file_t *file, apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_close (file),
"close", pool);
}
svn_error_t *
svn_io_file_getc (char *ch, apr_file_t *file, apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_getc (ch, file),
"read", pool);
}
svn_error_t *
svn_io_file_info_get (apr_finfo_t *finfo, apr_int32_t wanted,
apr_file_t *file, apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_info_get (finfo, wanted, file),
"get attribute information from", pool);
}
svn_error_t *
svn_io_file_read (apr_file_t *file, void *buf,
apr_size_t *nbytes, apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_read (file, buf, nbytes),
"read", pool);
}
svn_error_t *
svn_io_file_read_full (apr_file_t *file, void *buf,
apr_size_t nbytes, apr_size_t *bytes_read,
apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_read_full (file, buf, nbytes, bytes_read),
"read", pool);
}
svn_error_t *
svn_io_file_seek (apr_file_t *file, apr_seek_where_t where,
apr_off_t *offset, apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_seek (file, where, offset),
"set position pointer in", pool);
}
svn_error_t *
svn_io_file_write (apr_file_t *file, const void *buf,
apr_size_t *nbytes, apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_write (file, buf, nbytes),
"write to", pool);
}
svn_error_t *
svn_io_file_write_full (apr_file_t *file, const void *buf,
apr_size_t nbytes, apr_size_t *bytes_written,
apr_pool_t *pool)
{
return do_io_file_wrapper_cleanup
(file, apr_file_write_full (file, buf, nbytes, bytes_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -