Skip to content

Commit 06f46f2

Browse files
peffgitster
authored andcommitted
avoid "write_in_full(fd, buf, len) != len" pattern
The return value of write_in_full() is either "-1", or the requested number of bytes[1]. If we make a partial write before seeing an error, we still return -1, not a partial value. This goes back to f6aa66c (write_in_full: really write in full or return error on disk full., 2007-01-11). So checking anything except "was the return value negative" is pointless. And there are a couple of reasons not to do so: 1. It can do a funny signed/unsigned comparison. If your "len" is signed (e.g., a size_t) then the compiler will promote the "-1" to its unsigned variant. This works out for "!= len" (unless you really were trying to write the maximum size_t bytes), but is a bug if you check "< len" (an example of which was fixed recently in config.c). We should avoid promoting the mental model that you need to check the length at all, so that new sites are not tempted to copy us. 2. Checking for a negative value is shorter to type, especially when the length is an expression. 3. Linus says so. In d34cf19 (Clean up write_in_full() users, 2007-01-11), right after the write_in_full() semantics were changed, he wrote: I really wish every "write_in_full()" user would just check against "<0" now, but this fixes the nasty and stupid ones. Appeals to authority aside, this makes it clear that writing it this way does not have an intentional benefit. It's a historical curiosity that we never bothered to clean up (and which was undoubtedly cargo-culted into new sites). So let's convert these obviously-correct cases (this includes write_str_in_full(), which is just a wrapper for write_in_full()). [1] A careful reader may notice there is one way that write_in_full() can return a different value. If we ask write() to write N bytes and get a return value that is _larger_ than N, we could return a larger total. But besides the fact that this would imply a totally broken version of write(), it would already invoke undefined behavior. Our internal remaining counter is an unsigned size_t, which means that subtracting too many byte will wrap it around to a very large number. So we'll instantly begin reading off the end of the buffer, trying to write gigabytes (or petabytes) of data. Signed-off-by: Jeff King <[email protected]> Reviewed-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 68a423a commit 06f46f2

16 files changed

+26
-27
lines changed

builtin/receive-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
742742
size_t n;
743743
if (feed(feed_state, &buf, &n))
744744
break;
745-
if (write_in_full(proc.in, buf, n) != n)
745+
if (write_in_full(proc.in, buf, n) < 0)
746746
break;
747747
}
748748
close(proc.in);

builtin/rerere.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
1818
{
1919
int i;
2020
for (i = 0; i < nbuf; i++)
21-
if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)
21+
if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)
2222
return -1;
2323
return 0;
2424
}

builtin/unpack-file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ static char *create_temp_file(unsigned char *sha1)
1515

1616
xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
1717
fd = xmkstemp(path);
18-
if (write_in_full(fd, buf, size) != size)
18+
if (write_in_full(fd, buf, size) < 0)
1919
die_errno("unable to write temp-file");
2020
close(fd);
2121
return path;

config.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,7 +2565,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
25652565
copy_end - copy_begin) < 0)
25662566
goto write_err_out;
25672567
if (new_line &&
2568-
write_str_in_full(fd, "\n") != 1)
2568+
write_str_in_full(fd, "\n") < 0)
25692569
goto write_err_out;
25702570
}
25712571
copy_begin = store.offset[i];
@@ -2796,7 +2796,7 @@ int git_config_rename_section_in_file(const char *config_filename,
27962796
if (remove)
27972797
continue;
27982798
length = strlen(output);
2799-
if (write_in_full(out_fd, output, length) != length) {
2799+
if (write_in_full(out_fd, output, length) < 0) {
28002800
ret = write_error(get_lock_file_path(lock));
28012801
goto out;
28022802
}

diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2975,7 +2975,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
29752975
blob = buf.buf;
29762976
size = buf.len;
29772977
}
2978-
if (write_in_full(fd, blob, size) != size)
2978+
if (write_in_full(fd, blob, size) < 0)
29792979
die_errno("unable to write temp-file");
29802980
close_tempfile(&temp->tempfile);
29812981
temp->name = get_tempfile_path(&temp->tempfile);

fast-import.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2951,7 +2951,7 @@ static void parse_reset_branch(const char *arg)
29512951

29522952
static void cat_blob_write(const char *buf, unsigned long size)
29532953
{
2954-
if (write_in_full(cat_blob_fd, buf, size) != size)
2954+
if (write_in_full(cat_blob_fd, buf, size) < 0)
29552955
die_errno("Write to frontend failed");
29562956
}
29572957

http-backend.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ static void inflate_request(const char *prog_name, int out, int buffer_input)
357357
die("zlib error inflating request, result %d", ret);
358358

359359
n = stream.total_out - cnt;
360-
if (write_in_full(out, out_buf, n) != n)
360+
if (write_in_full(out, out_buf, n) < 0)
361361
die("%s aborted reading request", prog_name);
362362
cnt += n;
363363

@@ -378,7 +378,7 @@ static void copy_request(const char *prog_name, int out)
378378
ssize_t n = read_request(0, &buf);
379379
if (n < 0)
380380
die_errno("error reading request body");
381-
if (write_in_full(out, buf, n) != n)
381+
if (write_in_full(out, buf, n) < 0)
382382
die("%s aborted reading request", prog_name);
383383
close(out);
384384
free(buf);

ll-merge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ static void create_temp(mmfile_t *src, char *path, size_t len)
154154

155155
xsnprintf(path, len, ".merge_file_XXXXXX");
156156
fd = xmkstemp(path);
157-
if (write_in_full(fd, src->ptr, src->size) != src->size)
157+
if (write_in_full(fd, src->ptr, src->size) < 0)
158158
die_errno("unable to write temp-file");
159159
close(fd);
160160
}

read-cache.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ static int ce_write_flush(git_SHA_CTX *context, int fd)
19211921
unsigned int buffered = write_buffer_len;
19221922
if (buffered) {
19231923
git_SHA1_Update(context, write_buffer, buffered);
1924-
if (write_in_full(fd, write_buffer, buffered) != buffered)
1924+
if (write_in_full(fd, write_buffer, buffered) < 0)
19251925
return -1;
19261926
write_buffer_len = 0;
19271927
}
@@ -1970,7 +1970,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
19701970

19711971
/* Flush first if not enough space for SHA1 signature */
19721972
if (left + 20 > WRITE_BUFFER_SIZE) {
1973-
if (write_in_full(fd, write_buffer, left) != left)
1973+
if (write_in_full(fd, write_buffer, left) < 0)
19741974
return -1;
19751975
left = 0;
19761976
}
@@ -1979,7 +1979,7 @@ static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
19791979
git_SHA1_Final(write_buffer + left, context);
19801980
hashcpy(sha1, write_buffer + left);
19811981
left += 20;
1982-
return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
1982+
return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
19831983
}
19841984

19851985
static void ce_smudge_racily_clean_entry(struct cache_entry *ce)

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
592592
}
593593
}
594594

595-
if (write_in_full(fd, buf.buf, buf.len) != buf.len) {
595+
if (write_in_full(fd, buf.buf, buf.len) < 0) {
596596
strbuf_addf(err, "could not write to '%s'", filename);
597597
rollback_lock_file(&lock);
598598
goto done;

refs/files-backend.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,8 +2118,8 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
21182118
return -1;
21192119
}
21202120
fd = get_lock_file_fd(lock->lk);
2121-
if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ ||
2122-
write_in_full(fd, &term, 1) != 1 ||
2121+
if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) < 0 ||
2122+
write_in_full(fd, &term, 1) < 0 ||
21232123
close_ref(lock) < 0) {
21242124
strbuf_addf(err,
21252125
"couldn't write '%s'", get_lock_file_path(lock->lk));
@@ -3338,8 +3338,8 @@ static int files_reflog_expire(struct ref_store *ref_store,
33383338
strerror(errno));
33393339
} else if (update &&
33403340
(write_in_full(get_lock_file_fd(lock->lk),
3341-
oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ ||
3342-
write_str_in_full(get_lock_file_fd(lock->lk), "\n") != 1 ||
3341+
oid_to_hex(&cb.last_kept_oid), GIT_SHA1_HEXSZ) < 0 ||
3342+
write_str_in_full(get_lock_file_fd(lock->lk), "\n") < 0 ||
33433343
close_ref(lock) < 0)) {
33443344
status |= error("couldn't write %s",
33453345
get_lock_file_path(lock->lk));

rerere.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ static int write_rr(struct string_list *rr, int out_fd)
258258
rerere_id_hex(id),
259259
rr->items[i].string, 0);
260260

261-
if (write_in_full(out_fd, buf.buf, buf.len) != buf.len)
261+
if (write_in_full(out_fd, buf.buf, buf.len) < 0)
262262
die("unable to write rerere record");
263263

264264
strbuf_release(&buf);

shallow.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ const char *setup_temporary_shallow(const struct oid_array *extra)
296296
if (write_shallow_commits(&sb, 0, extra)) {
297297
fd = xmks_tempfile(&temporary_shallow, git_path("shallow_XXXXXX"));
298298

299-
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
299+
if (write_in_full(fd, sb.buf, sb.len) < 0)
300300
die_errno("failed to write to %s",
301301
get_tempfile_path(&temporary_shallow));
302302
close_tempfile(&temporary_shallow);
@@ -321,7 +321,7 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
321321
LOCK_DIE_ON_ERROR);
322322
check_shallow_file_for_update();
323323
if (write_shallow_commits(&sb, 0, extra)) {
324-
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
324+
if (write_in_full(fd, sb.buf, sb.len) < 0)
325325
die_errno("failed to write to %s",
326326
get_lock_file_path(shallow_lock));
327327
*alternate_shallow_file = get_lock_file_path(shallow_lock);
@@ -368,7 +368,7 @@ void prune_shallow(int show_only)
368368
LOCK_DIE_ON_ERROR);
369369
check_shallow_file_for_update();
370370
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
371-
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
371+
if (write_in_full(fd, sb.buf, sb.len) < 0)
372372
die_errno("failed to write to %s",
373373
get_lock_file_path(&shallow_lock));
374374
commit_lock_file(&shallow_lock);

t/helper/test-delta.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ int cmd_main(int argc, const char **argv)
6969
}
7070

7171
fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
72-
if (fd < 0 || write_in_full(fd, out_buf, out_size) != out_size) {
72+
if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) {
7373
perror(argv[4]);
7474
return 1;
7575
}

transport-helper.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer)
4444
{
4545
if (debug)
4646
fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf);
47-
if (write_in_full(helper->helper->in, buffer->buf, buffer->len)
48-
!= buffer->len)
47+
if (write_in_full(helper->helper->in, buffer->buf, buffer->len) < 0)
4948
die_errno("Full write to remote helper failed");
5049
}
5150

@@ -74,7 +73,7 @@ static void write_constant(int fd, const char *str)
7473
{
7574
if (debug)
7675
fprintf(stderr, "Debug: Remote helper: -> %s", str);
77-
if (write_in_full(fd, str, strlen(str)) != strlen(str))
76+
if (write_in_full(fd, str, strlen(str)) < 0)
7877
die_errno("Full write to remote helper failed");
7978
}
8079

wrapper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ int xsnprintf(char *dst, size_t max, const char *fmt, ...)
652652
void write_file_buf(const char *path, const char *buf, size_t len)
653653
{
654654
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
655-
if (write_in_full(fd, buf, len) != len)
655+
if (write_in_full(fd, buf, len) < 0)
656656
die_errno(_("could not write to %s"), path);
657657
if (close(fd))
658658
die_errno(_("could not close %s"), path);

0 commit comments

Comments
 (0)