Merge branch 'jk/write-in-full-fix'

Many codepaths did not diagnose write failures correctly when disks
go full, due to their misuse of write_in_full() helper function,
which have been corrected.

* jk/write-in-full-fix:
  read_pack_header: handle signed/unsigned comparison in read result
  config: flip return value of store_write_*()
  notes-merge: use ssize_t for write_in_full() return value
  pkt-line: check write_in_full() errors against "< 0"
  convert less-trivial versions of "write_in_full() != len"
  avoid "write_in_full(fd, buf, len) != len" pattern
  get-tar-commit-id: check write_in_full() return against 0
  config: avoid "write_in_full(fd, buf, len) < len" pattern
This commit is contained in:
Junio C Hamano 2017-09-25 15:24:06 +09:00
Родитель 94982b6999 f48ecd38cb
Коммит c50424a6f0
22 изменённых файлов: 65 добавлений и 67 удалений

Просмотреть файл

@ -33,8 +33,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
if (!skip_prefix(content, "52 comment=", &comment)) if (!skip_prefix(content, "52 comment=", &comment))
return 1; return 1;
n = write_in_full(1, comment, 41); if (write_in_full(1, comment, 41) < 0)
if (n < 41)
die_errno("git get-tar-commit-id: write error"); die_errno("git get-tar-commit-id: write error");
return 0; return 0;

Просмотреть файл

@ -743,7 +743,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
size_t n; size_t n;
if (feed(feed_state, &buf, &n)) if (feed(feed_state, &buf, &n))
break; break;
if (write_in_full(proc.in, buf, n) != n) if (write_in_full(proc.in, buf, n) < 0)
break; break;
} }
close(proc.in); close(proc.in);

Просмотреть файл

@ -18,7 +18,7 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
{ {
int i; int i;
for (i = 0; i < nbuf; i++) for (i = 0; i < nbuf; i++)
if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size) if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)
return -1; return -1;
return 0; return 0;
} }

Просмотреть файл

@ -15,7 +15,7 @@ static char *create_temp_file(struct object_id *oid)
xsnprintf(path, sizeof(path), ".merge_file_XXXXXX"); xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
fd = xmkstemp(path); fd = xmkstemp(path);
if (write_in_full(fd, buf, size) != size) if (write_in_full(fd, buf, size) < 0)
die_errno("unable to write temp-file"); die_errno("unable to write temp-file");
close(fd); close(fd);
return path; return path;

Просмотреть файл

@ -2292,10 +2292,11 @@ static int write_error(const char *filename)
return 4; return 4;
} }
static int store_write_section(int fd, const char *key) static ssize_t write_section(int fd, const char *key)
{ {
const char *dot; const char *dot;
int i, success; int i;
ssize_t ret;
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
dot = memchr(key, '.', store.baselen); dot = memchr(key, '.', store.baselen);
@ -2311,15 +2312,16 @@ static int store_write_section(int fd, const char *key)
strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
} }
success = write_in_full(fd, sb.buf, sb.len) == sb.len; ret = write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb); strbuf_release(&sb);
return success; return ret;
} }
static int store_write_pair(int fd, const char *key, const char *value) static ssize_t write_pair(int fd, const char *key, const char *value)
{ {
int i, success; int i;
ssize_t ret;
int length = strlen(key + store.baselen + 1); int length = strlen(key + store.baselen + 1);
const char *quote = ""; const char *quote = "";
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
@ -2359,10 +2361,10 @@ static int store_write_pair(int fd, const char *key, const char *value)
} }
strbuf_addf(&sb, "%s\n", quote); strbuf_addf(&sb, "%s\n", quote);
success = write_in_full(fd, sb.buf, sb.len) == sb.len; ret = write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb); strbuf_release(&sb);
return success; return ret;
} }
static ssize_t find_beginning_of_line(const char *contents, size_t size, static ssize_t find_beginning_of_line(const char *contents, size_t size,
@ -2491,8 +2493,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
} }
store.key = (char *)key; store.key = (char *)key;
if (!store_write_section(fd, key) || if (write_section(fd, key) < 0 ||
!store_write_pair(fd, key, value)) write_pair(fd, key, value) < 0)
goto write_err_out; goto write_err_out;
} else { } else {
struct stat st; struct stat st;
@ -2602,11 +2604,10 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
/* write the first part of the config */ /* write the first part of the config */
if (copy_end > copy_begin) { if (copy_end > copy_begin) {
if (write_in_full(fd, contents + copy_begin, if (write_in_full(fd, contents + copy_begin,
copy_end - copy_begin) < copy_end - copy_begin) < 0)
copy_end - copy_begin)
goto write_err_out; goto write_err_out;
if (new_line && if (new_line &&
write_str_in_full(fd, "\n") != 1) write_str_in_full(fd, "\n") < 0)
goto write_err_out; goto write_err_out;
} }
copy_begin = store.offset[i]; copy_begin = store.offset[i];
@ -2615,18 +2616,17 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
/* write the pair (value == NULL means unset) */ /* write the pair (value == NULL means unset) */
if (value != NULL) { if (value != NULL) {
if (store.state == START) { if (store.state == START) {
if (!store_write_section(fd, key)) if (write_section(fd, key) < 0)
goto write_err_out; goto write_err_out;
} }
if (!store_write_pair(fd, key, value)) if (write_pair(fd, key, value) < 0)
goto write_err_out; goto write_err_out;
} }
/* write the rest of the config */ /* write the rest of the config */
if (copy_begin < contents_sz) if (copy_begin < contents_sz)
if (write_in_full(fd, contents + copy_begin, if (write_in_full(fd, contents + copy_begin,
contents_sz - copy_begin) < contents_sz - copy_begin) < 0)
contents_sz - copy_begin)
goto write_err_out; goto write_err_out;
munmap(contents, contents_sz); munmap(contents, contents_sz);
@ -2803,7 +2803,7 @@ int git_config_rename_section_in_file(const char *config_filename,
continue; continue;
} }
store.baselen = strlen(new_name); store.baselen = strlen(new_name);
if (!store_write_section(out_fd, new_name)) { if (write_section(out_fd, new_name) < 0) {
ret = write_error(get_lock_file_path(lock)); ret = write_error(get_lock_file_path(lock));
goto out; goto out;
} }
@ -2829,7 +2829,7 @@ int git_config_rename_section_in_file(const char *config_filename,
if (remove) if (remove)
continue; continue;
length = strlen(output); length = strlen(output);
if (write_in_full(out_fd, output, length) != length) { if (write_in_full(out_fd, output, length) < 0) {
ret = write_error(get_lock_file_path(lock)); ret = write_error(get_lock_file_path(lock));
goto out; goto out;
} }

2
diff.c
Просмотреть файл

@ -3738,7 +3738,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
blob = buf.buf; blob = buf.buf;
size = buf.len; size = buf.len;
} }
if (write_in_full(temp->tempfile->fd, blob, size) != size || if (write_in_full(temp->tempfile->fd, blob, size) < 0 ||
close_tempfile_gently(temp->tempfile)) close_tempfile_gently(temp->tempfile))
die_errno("unable to write temp-file"); die_errno("unable to write temp-file");
temp->name = get_tempfile_path(temp->tempfile); temp->name = get_tempfile_path(temp->tempfile);

Просмотреть файл

@ -257,7 +257,8 @@ static int write_entry(struct cache_entry *ce,
char *new; char *new;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
unsigned long size; unsigned long size;
size_t wrote, newsize = 0; ssize_t wrote;
size_t newsize = 0;
struct stat st; struct stat st;
const struct submodule *sub; const struct submodule *sub;
@ -332,7 +333,7 @@ static int write_entry(struct cache_entry *ce,
fstat_done = fstat_output(fd, state, &st); fstat_done = fstat_output(fd, state, &st);
close(fd); close(fd);
free(new); free(new);
if (wrote != size) if (wrote < 0)
return error("unable to write file %s", path); return error("unable to write file %s", path);
break; break;
case S_IFGITLINK: case S_IFGITLINK:

Просмотреть файл

@ -2952,7 +2952,7 @@ static void parse_reset_branch(const char *arg)
static void cat_blob_write(const char *buf, unsigned long size) static void cat_blob_write(const char *buf, unsigned long size)
{ {
if (write_in_full(cat_blob_fd, buf, size) != size) if (write_in_full(cat_blob_fd, buf, size) < 0)
die_errno("Write to frontend failed"); die_errno("Write to frontend failed");
} }

Просмотреть файл

@ -358,7 +358,7 @@ static void inflate_request(const char *prog_name, int out, int buffer_input)
die("zlib error inflating request, result %d", ret); die("zlib error inflating request, result %d", ret);
n = stream.total_out - cnt; n = stream.total_out - cnt;
if (write_in_full(out, out_buf, n) != n) if (write_in_full(out, out_buf, n) < 0)
die("%s aborted reading request", prog_name); die("%s aborted reading request", prog_name);
cnt += n; cnt += n;
@ -379,7 +379,7 @@ static void copy_request(const char *prog_name, int out)
ssize_t n = read_request(0, &buf); ssize_t n = read_request(0, &buf);
if (n < 0) if (n < 0)
die_errno("error reading request body"); die_errno("error reading request body");
if (write_in_full(out, buf, n) != n) if (write_in_full(out, buf, n) < 0)
die("%s aborted reading request", prog_name); die("%s aborted reading request", prog_name);
close(out); close(out);
free(buf); free(buf);

Просмотреть файл

@ -154,7 +154,7 @@ static void create_temp(mmfile_t *src, char *path, size_t len)
xsnprintf(path, len, ".merge_file_XXXXXX"); xsnprintf(path, len, ".merge_file_XXXXXX");
fd = xmkstemp(path); fd = xmkstemp(path);
if (write_in_full(fd, src->ptr, src->size) != src->size) if (write_in_full(fd, src->ptr, src->size) < 0)
die_errno("unable to write temp-file"); die_errno("unable to write temp-file");
close(fd); close(fd);
} }

Просмотреть файл

@ -302,7 +302,7 @@ static void write_buf_to_worktree(const struct object_id *obj,
fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666); fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
while (size > 0) { while (size > 0) {
long ret = write_in_full(fd, buf, size); ssize_t ret = write_in_full(fd, buf, size);
if (ret < 0) { if (ret < 0) {
/* Ignore epipe */ /* Ignore epipe */
if (errno == EPIPE) if (errno == EPIPE)

Просмотреть файл

@ -94,9 +94,9 @@ void packet_flush(int fd)
int packet_flush_gently(int fd) int packet_flush_gently(int fd)
{ {
packet_trace("0000", 4, 1); packet_trace("0000", 4, 1);
if (write_in_full(fd, "0000", 4) == 4) if (write_in_full(fd, "0000", 4) < 0)
return 0;
return error("flush packet write failed"); return error("flush packet write failed");
return 0;
} }
void packet_buf_flush(struct strbuf *buf) void packet_buf_flush(struct strbuf *buf)
@ -137,19 +137,18 @@ static int packet_write_fmt_1(int fd, int gently,
const char *fmt, va_list args) const char *fmt, va_list args)
{ {
static struct strbuf buf = STRBUF_INIT; static struct strbuf buf = STRBUF_INIT;
ssize_t count;
strbuf_reset(&buf); strbuf_reset(&buf);
format_packet(&buf, fmt, args); format_packet(&buf, fmt, args);
count = write_in_full(fd, buf.buf, buf.len); if (write_in_full(fd, buf.buf, buf.len) < 0) {
if (count == buf.len)
return 0;
if (!gently) { if (!gently) {
check_pipe(errno); check_pipe(errno);
die_errno("packet write with format failed"); die_errno("packet write with format failed");
} }
return error("packet write with format failed"); return error("packet write with format failed");
}
return 0;
} }
void packet_write_fmt(int fd, const char *fmt, ...) void packet_write_fmt(int fd, const char *fmt, ...)
@ -184,9 +183,9 @@ static int packet_write_gently(const int fd_out, const char *buf, size_t size)
packet_size = size + 4; packet_size = size + 4;
set_packet_header(packet_write_buffer, packet_size); set_packet_header(packet_write_buffer, packet_size);
memcpy(packet_write_buffer + 4, buf, size); memcpy(packet_write_buffer + 4, buf, size);
if (write_in_full(fd_out, packet_write_buffer, packet_size) == packet_size) if (write_in_full(fd_out, packet_write_buffer, packet_size) < 0)
return 0;
return error("packet write failed"); return error("packet write failed");
return 0;
} }
void packet_buf_write(struct strbuf *buf, const char *fmt, ...) void packet_buf_write(struct strbuf *buf, const char *fmt, ...)

Просмотреть файл

@ -1922,7 +1922,7 @@ static int ce_write_flush(git_SHA_CTX *context, int fd)
unsigned int buffered = write_buffer_len; unsigned int buffered = write_buffer_len;
if (buffered) { if (buffered) {
git_SHA1_Update(context, write_buffer, buffered); git_SHA1_Update(context, write_buffer, buffered);
if (write_in_full(fd, write_buffer, buffered) != buffered) if (write_in_full(fd, write_buffer, buffered) < 0)
return -1; return -1;
write_buffer_len = 0; write_buffer_len = 0;
} }
@ -1971,7 +1971,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
/* Flush first if not enough space for SHA1 signature */ /* Flush first if not enough space for SHA1 signature */
if (left + 20 > WRITE_BUFFER_SIZE) { if (left + 20 > WRITE_BUFFER_SIZE) {
if (write_in_full(fd, write_buffer, left) != left) if (write_in_full(fd, write_buffer, left) < 0)
return -1; return -1;
left = 0; left = 0;
} }
@ -1980,7 +1980,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
git_SHA1_Final(write_buffer + left, context); git_SHA1_Final(write_buffer + left, context);
hashcpy(sha1, write_buffer + left); hashcpy(sha1, write_buffer + left);
left += 20; left += 20;
return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0; return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
} }
static void ce_smudge_racily_clean_entry(struct cache_entry *ce) static void ce_smudge_racily_clean_entry(struct cache_entry *ce)

2
refs.c
Просмотреть файл

@ -609,7 +609,7 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
} }
} }
if (write_in_full(fd, buf.buf, buf.len) != buf.len) { if (write_in_full(fd, buf.buf, buf.len) < 0) {
strbuf_addf(err, "could not write to '%s'", filename); strbuf_addf(err, "could not write to '%s'", filename);
rollback_lock_file(&lock); rollback_lock_file(&lock);
goto done; goto done;

Просмотреть файл

@ -1549,7 +1549,7 @@ static int log_ref_write_fd(int fd, const struct object_id *old_oid,
written = len <= maxlen ? write_in_full(fd, logrec, len) : -1; written = len <= maxlen ? write_in_full(fd, logrec, len) : -1;
free(logrec); free(logrec);
if (written != len) if (written < 0)
return -1; return -1;
return 0; return 0;
@ -1628,8 +1628,8 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
return -1; return -1;
} }
fd = get_lock_file_fd(&lock->lk); fd = get_lock_file_fd(&lock->lk);
if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ || if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) < 0 ||
write_in_full(fd, &term, 1) != 1 || write_in_full(fd, &term, 1) < 0 ||
close_ref_gently(lock) < 0) { close_ref_gently(lock) < 0) {
strbuf_addf(err, strbuf_addf(err,
"couldn't write '%s'", get_lock_file_path(&lock->lk)); "couldn't write '%s'", get_lock_file_path(&lock->lk));
@ -3006,8 +3006,8 @@ static int files_reflog_expire(struct ref_store *ref_store,
rollback_lock_file(&reflog_lock); rollback_lock_file(&reflog_lock);
} else if (update && } else if (update &&
(write_in_full(get_lock_file_fd(&lock->lk), (write_in_full(get_lock_file_fd(&lock->lk),
oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ || oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) < 0 ||
write_str_in_full(get_lock_file_fd(&lock->lk), "\n") != 1 || write_str_in_full(get_lock_file_fd(&lock->lk), "\n") < 1 ||
close_ref_gently(lock) < 0)) { close_ref_gently(lock) < 0)) {
status |= error("couldn't write %s", status |= error("couldn't write %s",
get_lock_file_path(&lock->lk)); get_lock_file_path(&lock->lk));

Просмотреть файл

@ -258,7 +258,7 @@ static int write_rr(struct string_list *rr, int out_fd)
rerere_id_hex(id), rerere_id_hex(id),
rr->items[i].string, 0); rr->items[i].string, 0);
if (write_in_full(out_fd, buf.buf, buf.len) != buf.len) if (write_in_full(out_fd, buf.buf, buf.len) < 0)
die("unable to write rerere record"); die("unable to write rerere record");
strbuf_release(&buf); strbuf_release(&buf);

Просмотреть файл

@ -1850,7 +1850,7 @@ int index_path(struct object_id *oid, const char *path, struct stat *st, unsigne
int read_pack_header(int fd, struct pack_header *header) int read_pack_header(int fd, struct pack_header *header)
{ {
if (read_in_full(fd, header, sizeof(*header)) < sizeof(*header)) if (read_in_full(fd, header, sizeof(*header)) != sizeof(*header))
/* "eof before pack header was fully read" */ /* "eof before pack header was fully read" */
return PH_ERROR_EOF; return PH_ERROR_EOF;

Просмотреть файл

@ -294,7 +294,7 @@ const char *setup_temporary_shallow(const struct oid_array *extra)
if (write_shallow_commits(&sb, 0, extra)) { if (write_shallow_commits(&sb, 0, extra)) {
temp = xmks_tempfile(git_path("shallow_XXXXXX")); temp = xmks_tempfile(git_path("shallow_XXXXXX"));
if (write_in_full(temp->fd, sb.buf, sb.len) != sb.len || if (write_in_full(temp->fd, sb.buf, sb.len) < 0 ||
close_tempfile_gently(temp) < 0) close_tempfile_gently(temp) < 0)
die_errno("failed to write to %s", die_errno("failed to write to %s",
get_tempfile_path(temp)); get_tempfile_path(temp));
@ -319,7 +319,7 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
LOCK_DIE_ON_ERROR); LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(); check_shallow_file_for_update();
if (write_shallow_commits(&sb, 0, extra)) { if (write_shallow_commits(&sb, 0, extra)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len) if (write_in_full(fd, sb.buf, sb.len) < 0)
die_errno("failed to write to %s", die_errno("failed to write to %s",
get_lock_file_path(shallow_lock)); get_lock_file_path(shallow_lock));
*alternate_shallow_file = get_lock_file_path(shallow_lock); *alternate_shallow_file = get_lock_file_path(shallow_lock);
@ -366,7 +366,7 @@ void prune_shallow(int show_only)
LOCK_DIE_ON_ERROR); LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(); check_shallow_file_for_update();
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) { if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
if (write_in_full(fd, sb.buf, sb.len) != sb.len) if (write_in_full(fd, sb.buf, sb.len) < 0)
die_errno("failed to write to %s", die_errno("failed to write to %s",
get_lock_file_path(&shallow_lock)); get_lock_file_path(&shallow_lock));
commit_lock_file(&shallow_lock); commit_lock_file(&shallow_lock);

Просмотреть файл

@ -540,7 +540,7 @@ int stream_blob_to_fd(int fd, const struct object_id *oid, struct stream_filter
kept = 0; kept = 0;
wrote = write_in_full(fd, buf, readlen); wrote = write_in_full(fd, buf, readlen);
if (wrote != readlen) if (wrote < 0)
goto close_and_exit; goto close_and_exit;
} }
if (kept && (lseek(fd, kept - 1, SEEK_CUR) == (off_t) -1 || if (kept && (lseek(fd, kept - 1, SEEK_CUR) == (off_t) -1 ||

Просмотреть файл

@ -69,7 +69,7 @@ int cmd_main(int argc, const char **argv)
} }
fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666); fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0 || write_in_full(fd, out_buf, out_size) != out_size) { if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) {
perror(argv[4]); perror(argv[4]);
return 1; return 1;
} }

Просмотреть файл

@ -44,8 +44,7 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer)
{ {
if (debug) if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf); fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf);
if (write_in_full(helper->helper->in, buffer->buf, buffer->len) if (write_in_full(helper->helper->in, buffer->buf, buffer->len) < 0)
!= buffer->len)
die_errno("Full write to remote helper failed"); die_errno("Full write to remote helper failed");
} }
@ -74,7 +73,7 @@ static void write_constant(int fd, const char *str)
{ {
if (debug) if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", str); fprintf(stderr, "Debug: Remote helper: -> %s", str);
if (write_in_full(fd, str, strlen(str)) != strlen(str)) if (write_in_full(fd, str, strlen(str)) < 0)
die_errno("Full write to remote helper failed"); die_errno("Full write to remote helper failed");
} }

Просмотреть файл

@ -652,7 +652,7 @@ int xsnprintf(char *dst, size_t max, const char *fmt, ...)
void write_file_buf(const char *path, const char *buf, size_t len) void write_file_buf(const char *path, const char *buf, size_t len)
{ {
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (write_in_full(fd, buf, len) != len) if (write_in_full(fd, buf, len) < 0)
die_errno(_("could not write to %s"), path); die_errno(_("could not write to %s"), path);
if (close(fd)) if (close(fd))
die_errno(_("could not close %s"), path); die_errno(_("could not close %s"), path);