1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-07 11:36:15 +02:00

Merge branch 'nd/fopen-errors'

We often try to open a file for reading whose existence is
optional, and silently ignore errors from open/fopen; report such
errors if they are not due to missing files.

* nd/fopen-errors:
  mingw_fopen: report ENOENT for invalid file names
  mingw: verify that paths are not mistaken for remote nicknames
  log: fix memory leak in open_next_file()
  rerere.c: move error_errno() closer to the source system call
  print errno when reporting a system call error
  wrapper.c: make warn_on_inaccessible() static
  wrapper.c: add and use fopen_or_warn()
  wrapper.c: add and use warn_on_fopen_errors()
  config.mak.uname: set FREAD_READS_DIRECTORIES for Darwin, too
  config.mak.uname: set FREAD_READS_DIRECTORIES for Linux and FreeBSD
  clone: use xfopen() instead of fopen()
  use xfopen() in more places
  git_fopen: fix a sparse 'not declared' warning
This commit is contained in:
Junio C Hamano 2017-06-13 13:47:09 -07:00
commit b9a7d55d93
32 changed files with 125 additions and 92 deletions

7
attr.c
View File

@ -720,16 +720,13 @@ void git_attr_set_direction(enum git_attr_direction new_direction,
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
{
FILE *fp = fopen(path, "r");
FILE *fp = fopen_or_warn(path, "r");
struct attr_stack *res;
char buf[2048];
int lineno = 0;
if (!fp) {
if (errno != ENOENT && errno != ENOTDIR)
warn_on_inaccessible(path);
if (!fp)
return NULL;
}
res = xcalloc(1, sizeof(*res));
while (fgets(buf, sizeof(buf), fp)) {
char *bufp = buf;

View File

@ -438,10 +438,7 @@ static void read_bisect_paths(struct argv_array *array)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path_bisect_names();
FILE *fp = fopen(filename, "r");
if (!fp)
die_errno(_("Could not open file '%s'"), filename);
FILE *fp = xfopen(filename, "r");
while (strbuf_getline_lf(&str, fp) != EOF) {
strbuf_trim(&str);
@ -669,7 +666,7 @@ static int is_expected_rev(const struct object_id *oid)
if (stat(filename, &st) || !S_ISREG(st.st_mode))
return 0;
fp = fopen(filename, "r");
fp = fopen_or_warn(filename, "r");
if (!fp)
return 0;

View File

@ -1275,12 +1275,8 @@ static int parse_mail(struct am_state *state, const char *mail)
die("BUG: invalid value for state->scissors");
}
mi.input = fopen(mail, "r");
if (!mi.input)
die("could not open input");
mi.output = fopen(am_path(state, "info"), "w");
if (!mi.output)
die("could not open output 'info'");
mi.input = xfopen(mail, "r");
mi.output = xfopen(am_path(state, "info"), "w");
if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch")))
die("could not parse patch");

View File

@ -481,7 +481,7 @@ static void output(struct blame_scoreboard *sb, int option)
*/
static int read_ancestry(const char *graft_file)
{
FILE *fp = fopen(graft_file, "r");
FILE *fp = fopen_or_warn(graft_file, "r");
struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;

View File

@ -360,7 +360,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,
* to turn entries with paths relative to the original
* absolute, so that they can be used in the new repository.
*/
FILE *in = fopen(src->buf, "r");
FILE *in = xfopen(src->buf, "r");
struct strbuf line = STRBUF_INIT;
while (strbuf_getline(&line, in) != EOF) {

View File

@ -1699,10 +1699,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!reflog_msg)
reflog_msg = "commit (merge)";
pptr = commit_list_append(current_head, pptr);
fp = fopen(git_path_merge_head(), "r");
if (fp == NULL)
die_errno(_("could not open '%s' for reading"),
git_path_merge_head());
fp = xfopen(git_path_merge_head(), "r");
while (strbuf_getline_lf(&m, fp) != EOF) {
struct commit *parent;

View File

@ -907,9 +907,7 @@ static void export_marks(char *file)
static void import_marks(char *input_file)
{
char line[512];
FILE *f = fopen(input_file, "r");
if (!f)
die_errno("cannot read '%s'", input_file);
FILE *f = xfopen(input_file, "r");
while (fgets(line, sizeof(line), f)) {
uint32_t mark;

View File

@ -280,8 +280,7 @@ static void check_unreachable_object(struct object *obj)
free(filename);
return;
}
if (!(f = fopen(filename, "w")))
die_errno("Could not open '%s'", filename);
f = xfopen(filename, "w");
if (obj->type == OBJ_BLOB) {
if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
die_errno("Could not write '%s'", filename);

View File

@ -846,8 +846,10 @@ static int open_next_file(struct commit *commit, const char *subject,
if (output_directory) {
strbuf_addstr(&filename, output_directory);
if (filename.len >=
PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) {
strbuf_release(&filename);
return error(_("name of output directory is too long"));
}
strbuf_complete(&filename, '/');
}
@ -861,8 +863,11 @@ static int open_next_file(struct commit *commit, const char *subject,
if (!quiet)
printf("%s\n", filename.buf + outdir_offset);
if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL)
return error(_("Cannot open patch file %s"), filename.buf);
if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
error_errno(_("Cannot open patch file %s"), filename.buf);
strbuf_release(&filename);
return -1;
}
strbuf_release(&filename);
return 0;

View File

@ -839,9 +839,7 @@ static int suggest_conflicts(void)
struct strbuf msgbuf = STRBUF_INIT;
filename = git_path_merge_msg();
fp = fopen(filename, "a");
if (!fp)
die_errno(_("Could not open '%s' for writing"), filename);
fp = xfopen(filename, "a");
append_conflicts_hint(&msgbuf);
fputs(msgbuf.buf, fp);

View File

@ -337,8 +337,7 @@ static void get_merge_heads(struct oid_array *merge_heads)
struct strbuf sb = STRBUF_INIT;
struct object_id oid;
if (!(fp = fopen(filename, "r")))
die_errno(_("could not open '%s' for reading"), filename);
fp = xfopen(filename, "r");
while (strbuf_getline_lf(&sb, fp) != EOF) {
if (get_oid_hex(sb.buf, &oid))
continue; /* invalid line: does not start with SHA1 */

View File

@ -168,7 +168,7 @@ struct commit_graft *read_graft_line(char *buf, int len)
static int read_graft_file(const char *graft_file)
{
FILE *fp = fopen(graft_file, "r");
FILE *fp = fopen_or_warn(graft_file, "r");
struct strbuf buf = STRBUF_INIT;
if (!fp)
return -1;

View File

@ -1,14 +1,14 @@
/*
* The order of the following two lines is important.
*
* FREAD_READS_DIRECTORIES is undefined before including git-compat-util.h
* SUPPRESS_FOPEN_REDEFINITION is defined before including git-compat-util.h
* to avoid the redefinition of fopen within git-compat-util.h. This is
* necessary since fopen is a macro on some platforms which may be set
* based on compiler options. For example, on AIX fopen is set to fopen64
* when _LARGE_FILES is defined. The previous technique of merely undefining
* fopen after including git-compat-util.h is inadequate in this case.
*/
#undef FREAD_READS_DIRECTORIES
#define SUPPRESS_FOPEN_REDEFINITION
#include "../git-compat-util.h"
FILE *git_fopen(const char *path, const char *mode)

View File

@ -423,6 +423,8 @@ FILE *mingw_fopen (const char *filename, const char *otype)
return NULL;
}
file = _wfopen(wfilename, wotype);
if (!file && GetLastError() == ERROR_INVALID_NAME)
errno = ENOENT;
if (file && hide && set_hidden_flag(wfilename, 1))
warning("could not mark '%s' as hidden.", filename);
return file;

View File

@ -1438,7 +1438,7 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
int ret = -1;
FILE *f;
f = fopen(filename, "r");
f = fopen_or_warn(filename, "r");
if (f) {
flockfile(f);
ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data);
@ -2656,6 +2656,9 @@ int git_config_rename_section_in_file(const char *config_filename,
}
if (!(config_file = fopen(config_filename, "rb"))) {
ret = warn_on_fopen_errors(config_filename);
if (ret)
goto out;
/* no config file means nothing to rename, no error */
goto commit_and_out;
}

View File

@ -36,6 +36,7 @@ ifeq ($(uname_S),Linux)
NEEDS_LIBRT = YesPlease
HAVE_GETDELIM = YesPlease
SANE_TEXT_GREP=-a
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_ALLOCA_H = YesPlease
@ -43,6 +44,7 @@ ifeq ($(uname_S),GNU/kFreeBSD)
HAVE_PATHS_H = YesPlease
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
LIBC_CONTAINS_LIBINTL = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),UnixWare)
CC = cc
@ -108,6 +110,7 @@ ifeq ($(uname_S),Darwin)
BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
HAVE_BSD_SYSCTL = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@ -201,6 +204,7 @@ ifeq ($(uname_S),FreeBSD)
GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes
HAVE_BSD_SYSCTL = YesPlease
PAGER_ENV = LESS=FRX LV=-c MORE=FRX
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease

8
diff.c
View File

@ -4071,9 +4071,7 @@ int diff_opt_parse(struct diff_options *options,
DIFF_OPT_CLR(options, FUNCCONTEXT);
else if ((argcount = parse_long_opt("output", av, &optarg))) {
char *path = prefix_filename(prefix, optarg);
options->file = fopen(path, "w");
if (!options->file)
die_errno("Could not open '%s'", path);
options->file = xfopen(path, "w");
options->close_file = 1;
if (options->use_color != GIT_COLOR_ALWAYS)
options->use_color = GIT_COLOR_NEVER;
@ -4807,9 +4805,7 @@ void diff_flush(struct diff_options *options)
*/
if (options->close_file)
fclose(options->file);
options->file = fopen("/dev/null", "w");
if (!options->file)
die_errno("Could not open /dev/null");
options->file = xfopen("/dev/null", "w");
options->close_file = 1;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];

6
dir.c
View File

@ -752,9 +752,9 @@ static int add_excludes(const char *fname, const char *base, int baselen,
fd = open(fname, O_RDONLY);
if (fd < 0 || fstat(fd, &st) < 0) {
if (errno != ENOENT)
warn_on_inaccessible(fname);
if (0 <= fd)
if (fd < 0)
warn_on_fopen_errors(fname);
else
close(fd);
if (!istate ||
(buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL)

View File

@ -3285,9 +3285,7 @@ static void option_export_pack_edges(const char *edges)
{
if (pack_edges)
fclose(pack_edges);
pack_edges = fopen(edges, "a");
if (!pack_edges)
die_errno("Cannot open '%s'", edges);
pack_edges = xfopen(edges, "a");
}
static int parse_one_option(const char *option)

View File

@ -693,10 +693,12 @@ char *gitstrdup(const char *s);
#endif
#ifdef FREAD_READS_DIRECTORIES
#ifdef fopen
#undef fopen
#endif
#define fopen(a,b) git_fopen(a,b)
# if !defined(SUPPRESS_FOPEN_REDEFINITION)
# ifdef fopen
# undef fopen
# endif
# define fopen(a,b) git_fopen(a,b)
# endif
extern FILE *git_fopen(const char*, const char*);
#endif
@ -804,6 +806,7 @@ extern int xmkstemp(char *template);
extern int xmkstemp_mode(char *template, int mode);
extern char *xgetcwd(void);
extern FILE *fopen_for_writing(const char *path);
extern FILE *fopen_or_warn(const char *path, const char *mode);
#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))
#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
@ -1110,8 +1113,8 @@ int remove_or_warn(unsigned int mode, const char *path);
int access_or_warn(const char *path, int mode, unsigned flag);
int access_or_die(const char *path, int mode, unsigned flag);
/* Warn on an inaccessible file that ought to be accessible */
void warn_on_inaccessible(const char *path);
/* Warn on an inaccessible file if errno indicates this is an error */
int warn_on_fopen_errors(const char *path);
#ifdef GMTIME_UNRELIABLE_ERRORS
struct tm *git_gmtime(const time_t *);

View File

@ -72,12 +72,10 @@ static int add_mailname_host(struct strbuf *buf)
FILE *mailname;
struct strbuf mailnamebuf = STRBUF_INIT;
mailname = fopen("/etc/mailname", "r");
if (!mailname) {
if (errno != ENOENT)
warning_errno("cannot open /etc/mailname");
mailname = fopen_or_warn("/etc/mailname", "r");
if (!mailname)
return -1;
}
if (strbuf_getline(&mailnamebuf, mailname) == EOF) {
if (ferror(mailname))
warning_errno("cannot read /etc/mailname");

View File

@ -124,10 +124,8 @@ static int note2mark_cb(const unsigned char *object_sha1,
static void regenerate_marks(void)
{
int ret;
FILE *marksfile = fopen(marksfilename, "w+");
FILE *marksfile = xfopen(marksfilename, "w+");
if (!marksfile)
die_errno("Couldn't create mark file %s.", marksfilename);
ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
if (ret)
die("Regeneration of marks failed, returned %d.", ret);
@ -148,9 +146,7 @@ static void check_or_regenerate_marks(int latestrev)
marksfile = fopen(marksfilename, "r");
if (!marksfile) {
regenerate_marks();
marksfile = fopen(marksfilename, "r");
if (!marksfile)
die_errno("cannot read marks file %s!", marksfilename);
marksfile = xfopen(marksfilename, "r");
fclose(marksfile);
} else {
strbuf_addf(&sb, ":%d ", latestrev);

View File

@ -251,7 +251,7 @@ static const char *skip_spaces(const char *s)
static void read_remotes_file(struct remote *remote)
{
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
FILE *f = fopen_or_warn(git_path("remotes/%s", remote->name), "r");
if (!f)
return;
@ -277,7 +277,7 @@ static void read_branches_file(struct remote *remote)
{
char *frag;
struct strbuf buf = STRBUF_INIT;
FILE *f = fopen(git_path("branches/%s", remote->name), "r");
FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r");
if (!f)
return;

View File

@ -200,7 +200,7 @@ static struct rerere_id *new_rerere_id(unsigned char *sha1)
static void read_rr(struct string_list *rr)
{
struct strbuf buf = STRBUF_INIT;
FILE *in = fopen(git_path_merge_rr(), "r");
FILE *in = fopen_or_warn(git_path_merge_rr(), "r");
if (!in)
return;
@ -484,13 +484,14 @@ static int handle_file(const char *path, unsigned char *sha1, const char *output
io.input = fopen(path, "r");
io.io.wrerror = 0;
if (!io.input)
return error("Could not open %s", path);
return error_errno("Could not open %s", path);
if (output) {
io.io.output = fopen(output, "w");
if (!io.io.output) {
error_errno("Could not write %s", output);
fclose(io.input);
return error("Could not write %s", output);
return -1;
}
}

View File

@ -899,8 +899,8 @@ static void flush_rewritten_pending(void) {
FILE *out;
if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), 82) > 0 &&
!get_sha1("HEAD", newsha1) &&
(out = fopen(rebase_path_rewritten_list(), "a"))) {
!get_sha1("HEAD", newsha1) &&
(out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
char *bol = buf.buf, *eol;
while (*bol) {
@ -919,7 +919,7 @@ static void flush_rewritten_pending(void) {
static void record_in_rewritten(struct object_id *oid,
enum todo_command next_command) {
FILE *out = fopen(rebase_path_rewritten_pending(), "a");
FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a");
if (!out)
return;
@ -1381,7 +1381,7 @@ static int read_populate_todo(struct todo_list *todo_list,
if (is_rebase_i(opts)) {
struct todo_list done = TODO_LIST_INIT;
FILE *f = fopen(rebase_path_msgtotal(), "w");
FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
!parse_insn_buffer(done.buf.buf, &done))

View File

@ -133,7 +133,7 @@ static int read_pack_info_file(const char *infofile)
char line[1000];
int old_cnt = 0;
fp = fopen(infofile, "r");
fp = fopen_or_warn(infofile, "r");
if (!fp)
return 1; /* nonexistent is not an error. */

View File

@ -183,11 +183,22 @@ test_expect_success 'proper error on non-existent files' '
test_cmp expect actual
'
test_expect_success 'proper error on directory "files"' '
echo "Error (-1) reading configuration file a-directory." >expect &&
mkdir a-directory &&
test_expect_code 2 test-config configset_get_value foo.bar a-directory 2>output &&
grep "^warning:" output &&
grep "^Error" output >actual &&
test_cmp expect actual
'
test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' '
chmod -r .git/config &&
test_when_finished "chmod +r .git/config" &&
echo "Error (-1) reading configuration file .git/config." >expect &&
test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>actual &&
test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>output &&
grep "^warning:" output &&
grep "^Error" output >actual &&
test_cmp expect actual
'

View File

@ -85,8 +85,15 @@ test_expect_success 'use branch.<name>.remote if possible' '
'
test_expect_success 'confuses pattern as remote when no remote specified' '
cat >exp <<-\EOF &&
fatal: '\''refs*master'\'' does not appear to be a git repository
if test_have_prereq MINGW
then
# Windows does not like asterisks in pathname
does_not_exist=master
else
does_not_exist="refs*master"
fi &&
cat >exp <<-EOF &&
fatal: '\''$does_not_exist'\'' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
@ -98,7 +105,7 @@ test_expect_success 'confuses pattern as remote when no remote specified' '
# fetch <branch>.
# We could just as easily have used "master"; the "*" emphasizes its
# role as a pattern.
test_must_fail git ls-remote refs*master >actual 2>&1 &&
test_must_fail git ls-remote "$does_not_exist" >actual 2>&1 &&
test_i18ncmp exp actual
'

View File

@ -1,10 +1,10 @@
#!/bin/sh
test_description='various UNC path tests (Windows-only)'
test_description='various Windows-only path tests'
. ./test-lib.sh
if ! test_have_prereq MINGW; then
skip_all='skipping UNC path tests, requires Windows'
skip_all='skipping Windows-only path tests'
test_done
fi
@ -45,4 +45,10 @@ test_expect_success push '
test "$rev" = "$(git rev-parse --verify refs/heads/to-push)"
'
test_expect_success 'remote nick cannot contain backslashes' '
BACKSLASHED="$(pwd | tr / \\\\)" &&
git ls-remote "$BACKSLASHED" >out 2>err &&
test_i18ngrep ! "unable to access" err
'
test_done

View File

@ -418,6 +418,32 @@ FILE *fopen_for_writing(const char *path)
return ret;
}
static void warn_on_inaccessible(const char *path)
{
warning_errno(_("unable to access '%s'"), path);
}
int warn_on_fopen_errors(const char *path)
{
if (errno != ENOENT && errno != ENOTDIR) {
warn_on_inaccessible(path);
return -1;
}
return 0;
}
FILE *fopen_or_warn(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if (fp)
return fp;
warn_on_fopen_errors(path);
return NULL;
}
int xmkstemp(char *template)
{
int fd;
@ -576,11 +602,6 @@ int remove_or_warn(unsigned int mode, const char *file)
return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
}
void warn_on_inaccessible(const char *path)
{
warning_errno(_("unable to access '%s'"), path);
}
static int access_error_is_ok(int err, unsigned flag)
{
return (is_missing_file_error(err) ||

View File

@ -1066,7 +1066,8 @@ static void show_am_in_progress(struct wt_status *s,
static char *read_line_from_git_path(const char *filename)
{
struct strbuf buf = STRBUF_INIT;
FILE *fp = fopen(git_path("%s", filename), "r");
FILE *fp = fopen_or_warn(git_path("%s", filename), "r");
if (!fp) {
strbuf_release(&buf);
return NULL;

View File

@ -164,9 +164,9 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
size_t sz;
if (stat(filename, &st))
return error("Could not stat %s", filename);
return error_errno("Could not stat %s", filename);
if ((f = fopen(filename, "rb")) == NULL)
return error("Could not open %s", filename);
return error_errno("Could not open %s", filename);
sz = xsize_t(st.st_size);
ptr->ptr = xmalloc(sz ? sz : 1);
if (sz && fread(ptr->ptr, sz, 1, f) != 1) {