{"thread":{"id":"6233","subject":"[PATCH] use xread where we are not checking for EAGAIN/EINTR","startedAt":"2007-01-05T10:54:33Z","lastAt":"2007-01-11T21:43:40Z","messageCount":10,"participants":["Andy Whitcroft","Junio C Hamano","Eric Wong"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"30874","messageId":"1cb8699724ff000fbf0c14ba3e15031e@pinky","threadId":"6233","inReplyTo":null,"subject":"[PATCH] use xread where we are not checking for EAGAIN/EINTR","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-05T10:54:33Z","receivedAt":"2007-01-05T10:54:33Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nWe have xread() to handle those OS's which will return EAGAIN or\nEINTR when the read is interrupted.  We should use this where we\nare not otherwise handling such errors.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n\n    We have an xread() wrapper to help us with those nasty\n    interrupt returns and yet we fail to use it consistently.\n    This patch updates those plain read()'s which do not\n    have any handling for errors, or which treat those errors\n    as user visible fatal errors.\n\n    This feels right to me, but perhaps there is some good\n    reason that things are done this way ... if so could\n    someone elighten me.\n\n    If this is a sensible change, then I'll have a look at\n    the write side.\n---\ndiff --git a/dir.c b/dir.c\nindex 0338d6c..8fe0865 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -142,7 +142,7 @@ static int add_excludes_from_file_1(const char *fname,\n \t\treturn 0;\n \t}\n \tbuf = xmalloc(size+1);\n-\tif (read(fd, buf, size) != size)\n+\tif (xread(fd, buf, size) != size)\n \t\tgoto err;\n \tclose(fd);\n \ndiff --git a/http-fetch.c b/http-fetch.c\nindex 396552d..50a3b00 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -175,7 +175,7 @@ static void start_object_request(struct object_request *obj_req)\n \tprevlocal = open(prevfile, O_RDONLY);\n \tif (prevlocal != -1) {\n \t\tdo {\n-\t\t\tprev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);\n+\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n \t\t\tif (prev_read>0) {\n \t\t\t\tif (fwrite_sha1_file(prev_buf,\n \t\t\t\t\t\t     1,\ndiff --git a/http-push.c b/http-push.c\nindex ecefdfd..acb5c27 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -288,7 +288,7 @@ static void start_fetch_loose(struct transfer_request *request)\n \tprevlocal = open(prevfile, O_RDONLY);\n \tif (prevlocal != -1) {\n \t\tdo {\n-\t\t\tprev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);\n+\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n \t\t\tif (prev_read>0) {\n \t\t\t\tif (fwrite_sha1_file(prev_buf,\n \t\t\t\t\t\t     1,\ndiff --git a/imap-send.c b/imap-send.c\nindex ad91858..3f1e542 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -224,7 +224,7 @@ socket_perror( const char *func, Socket_t *sock, int ret )\n static int\n socket_read( Socket_t *sock, char *buf, int len )\n {\n-\tint n = read( sock->fd, buf, len );\n+\tint n = xread( sock->fd, buf, len );\n \tif (n <= 0) {\n \t\tsocket_perror( \"read\", sock, n );\n \t\tclose( sock->fd );\n@@ -390,7 +390,7 @@ arc4_init( void )\n \t\tfprintf( stderr, \"Fatal: no random number source available.\\n\" );\n \t\texit( 3 );\n \t}\n-\tif (read( fd, dat, 128 ) != 128) {\n+\tif (xread( fd, dat, 128 ) != 128) {\n \t\tfprintf( stderr, \"Fatal: cannot read random number source.\\n\" );\n \t\texit( 3 );\n \t}\ndiff --git a/local-fetch.c b/local-fetch.c\nindex 7b6875c..21bcf75 100644\n--- a/local-fetch.c\n+++ b/local-fetch.c\n@@ -184,7 +184,7 @@ int fetch_ref(char *ref, unsigned char *sha1)\n \t\tfprintf(stderr, \"cannot open %s\\n\", filename);\n \t\treturn -1;\n \t}\n-\tif (read(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {\n+\tif (xread(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {\n \t\tclose(ifd);\n \t\tfprintf(stderr, \"cannot read from %s\\n\", filename);\n \t\treturn -1;\ndiff --git a/path.c b/path.c\nindex 066f621..f6f9cfd 100644\n--- a/path.c\n+++ b/path.c\n@@ -113,7 +113,7 @@ int validate_symref(const char *path)\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n \t\treturn -1;\n-\tlen = read(fd, buffer, sizeof(buffer)-1);\n+\tlen = xread(fd, buffer, sizeof(buffer)-1);\n \tclose(fd);\n \n \t/*\ndiff --git a/refs.c b/refs.c\nindex 121774c..f6afd61 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -284,7 +284,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *\n \t\tfd = open(path, O_RDONLY);\n \t\tif (fd < 0)\n \t\t\treturn NULL;\n-\t\tlen = read(fd, buffer, sizeof(buffer)-1);\n+\t\tlen = xread(fd, buffer, sizeof(buffer)-1);\n \t\tclose(fd);\n \n \t\t/*\ndiff --git a/sha1_file.c b/sha1_file.c\nindex d9622d9..0c9483c 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1869,7 +1869,7 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,\n \t\t\tif (ret != Z_OK)\n \t\t\t\tbreak;\n \t\t}\n-\t\tsize = read(fd, buffer + *bufposn, bufsize - *bufposn);\n+\t\tsize = xread(fd, buffer + *bufposn, bufsize - *bufposn);\n \t\tif (size <= 0) {\n \t\t\tclose(local);\n \t\t\tunlink(tmpfile);\ndiff --git a/ssh-fetch.c b/ssh-fetch.c\nindex b006c5c..6ec9488 100644\n--- a/ssh-fetch.c\n+++ b/ssh-fetch.c\n@@ -82,7 +82,7 @@ int fetch(unsigned char *sha1)\n \t\tremote = conn_buf[0];\n \t\tmemmove(conn_buf, conn_buf + 1, --conn_buf_posn);\n \t} else {\n-\t\tif (read(fd_in, &remote, 1) < 1)\n+\t\tif (xread(fd_in, &remote, 1) < 1)\n \t\t\treturn -1;\n \t}\n \t/* fprintf(stderr, \"Got %d\\n\", remote); */\n@@ -99,7 +99,7 @@ static int get_version(void)\n \tchar type = 'v';\n \twrite(fd_out, &type, 1);\n \twrite(fd_out, &local_version, 1);\n-\tif (read(fd_in, &remote_version, 1) < 1) {\n+\tif (xread(fd_in, &remote_version, 1) < 1) {\n \t\treturn error(\"Couldn't read version from remote end\");\n \t}\n \treturn 0;\n@@ -111,10 +111,10 @@ int fetch_ref(char *ref, unsigned char *sha1)\n \tchar type = 'r';\n \twrite(fd_out, &type, 1);\n \twrite(fd_out, ref, strlen(ref) + 1);\n-\tread(fd_in, &remote, 1);\n+\txread(fd_in, &remote, 1);\n \tif (remote < 0)\n \t\treturn remote;\n-\tread(fd_in, sha1, 20);\n+\txread(fd_in, sha1, 20);\n \treturn 0;\n }\n \ndiff --git a/ssh-upload.c b/ssh-upload.c\nindex 0b52ae1..3f2794c 100644\n--- a/ssh-upload.c\n+++ b/ssh-upload.c\n@@ -23,7 +23,7 @@ static int serve_object(int fd_in, int fd_out) {\n \tsigned char remote;\n \tint posn = 0;\n \tdo {\n-\t\tsize = read(fd_in, sha1 + posn, 20 - posn);\n+\t\tsize = xread(fd_in, sha1 + posn, 20 - posn);\n \t\tif (size < 0) {\n \t\t\tperror(\"git-ssh-upload: read \");\n \t\t\treturn -1;\n@@ -54,7 +54,7 @@ static int serve_object(int fd_in, int fd_out) {\n \n static int serve_version(int fd_in, int fd_out)\n {\n-\tif (read(fd_in, &remote_version, 1) < 1)\n+\tif (xread(fd_in, &remote_version, 1) < 1)\n \t\treturn -1;\n \twrite(fd_out, &local_version, 1);\n \treturn 0;\n@@ -67,7 +67,7 @@ static int serve_ref(int fd_in, int fd_out)\n \tint posn = 0;\n \tsigned char remote = 0;\n \tdo {\n-\t\tif (read(fd_in, ref + posn, 1) < 1)\n+\t\tif (xread(fd_in, ref + posn, 1) < 1)\n \t\t\treturn -1;\n \t\tposn++;\n \t} while (ref[posn - 1]);\n@@ -89,7 +89,7 @@ static void service(int fd_in, int fd_out) {\n \tchar type;\n \tint retval;\n \tdo {\n-\t\tretval = read(fd_in, &type, 1);\n+\t\tretval = xread(fd_in, &type, 1);\n \t\tif (retval < 1) {\n \t\t\tif (retval < 0)\n \t\t\t\tperror(\"git-ssh-upload: read \");\ndiff --git a/upload-pack.c b/upload-pack.c\nindex c568ef0..03a4156 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -242,7 +242,7 @@ static void create_pack_file(void)\n \t\t\t\t\t*cp++ = buffered;\n \t\t\t\t\toutsz++;\n \t\t\t\t}\n-\t\t\t\tsz = read(pu_pipe[0], cp,\n+\t\t\t\tsz = xread(pu_pipe[0], cp,\n \t\t\t\t\t  sizeof(data) - outsz);\n \t\t\t\tif (0 < sz)\n \t\t\t\t\t\t;\n@@ -267,7 +267,7 @@ static void create_pack_file(void)\n \t\t\t\t/* Status ready; we ship that in the side-band\n \t\t\t\t * or dump to the standard error.\n \t\t\t\t */\n-\t\t\t\tsz = read(pe_pipe[0], progress,\n+\t\t\t\tsz = xread(pe_pipe[0], progress,\n \t\t\t\t\t  sizeof(progress));\n \t\t\t\tif (0 < sz)\n \t\t\t\t\tsend_client_data(2, progress, sz);\n"},{"id":"30877","messageId":"7vvejlg1pg.fsf@assigned-by-dhcp.cox.net","threadId":"6233","inReplyTo":"1cb8699724ff000fbf0c14ba3e15031e@pinky","subject":"Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-01-05T11:19:55Z","receivedAt":"2007-01-05T11:19:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Whitcroft <apw@shadowen.org> writes:\n\n>     We have an xread() wrapper to help us with those nasty\n>     interrupt returns and yet we fail to use it consistently.\n>     This patch updates those plain read()'s which do not\n>     have any handling for errors, or which treat those errors\n>     as user visible fatal errors.\n>\n>     This feels right to me, but perhaps there is some good\n>     reason that things are done this way ... if so could\n>     someone elighten me.\n\nThanks.\n\nI do not think any of the changes you did introduced new bugs,\nbut I think some of them are still wrong.  xread() protects us\nfrom EINTR happening before any byte is read, but it can still\ngive a short read.  Many callers have a loop like this:\n\n\tdo {\n        \tsize = xread(...);\n                yet_to_go -= size;\n\t} while (yet_to_go);\n\nbut some are not (e.g. add_excludes_from_file_1() in dir.c\nexpects xread() does not return before reading full buffer).\n"},{"id":"30881","messageId":"459E4270.9090307@shadowen.org","threadId":"6233","inReplyTo":"7vvejlg1pg.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-05T12:20:00Z","receivedAt":"2007-01-05T12:20:00Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Andy Whitcroft <apw@shadowen.org> writes:\n> \n>>     We have an xread() wrapper to help us with those nasty\n>>     interrupt returns and yet we fail to use it consistently.\n>>     This patch updates those plain read()'s which do not\n>>     have any handling for errors, or which treat those errors\n>>     as user visible fatal errors.\n>>\n>>     This feels right to me, but perhaps there is some good\n>>     reason that things are done this way ... if so could\n>>     someone elighten me.\n> \n> Thanks.\n> \n> I do not think any of the changes you did introduced new bugs,\n> but I think some of them are still wrong.  xread() protects us\n> from EINTR happening before any byte is read, but it can still\n> give a short read.  Many callers have a loop like this:\n> \n> \tdo {\n>         \tsize = xread(...);\n>                 yet_to_go -= size;\n> \t} while (yet_to_go);\n> \n> but some are not (e.g. add_excludes_from_file_1() in dir.c\n> expects xread() does not return before reading full buffer).\n\nYes, that is true.  I was going to fix that in the next step with the\nwrites.  But yes thats likely to involve them becoming 'read_in_full'\nstyle thing and in fact churn us more.\n\nIgnore this one and I'll look to do it 'right'.\n\n-apw\n"},{"id":"31149","messageId":"45A2699F.5060100@shadowen.org","threadId":"6233","inReplyTo":"459E4270.9090307@shadowen.org","subject":"Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-08T15:56:15Z","receivedAt":"2007-01-08T15:56:15Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"Andy Whitcroft wrote:\n> Junio C Hamano wrote:\n>> Andy Whitcroft <apw@shadowen.org> writes:\n>>\n>>>     We have an xread() wrapper to help us with those nasty\n>>>     interrupt returns and yet we fail to use it consistently.\n>>>     This patch updates those plain read()'s which do not\n>>>     have any handling for errors, or which treat those errors\n>>>     as user visible fatal errors.\n>>>\n>>>     This feels right to me, but perhaps there is some good\n>>>     reason that things are done this way ... if so could\n>>>     someone elighten me.\n>> Thanks.\n>>\n>> I do not think any of the changes you did introduced new bugs,\n>> but I think some of them are still wrong.  xread() protects us\n>> from EINTR happening before any byte is read, but it can still\n>> give a short read.  Many callers have a loop like this:\n>>\n>> \tdo {\n>>         \tsize = xread(...);\n>>                 yet_to_go -= size;\n>> \t} while (yet_to_go);\n>>\n>> but some are not (e.g. add_excludes_from_file_1() in dir.c\n>> expects xread() does not return before reading full buffer).\n> \n> Yes, that is true.  I was going to fix that in the next step with the\n> writes.  But yes thats likely to involve them becoming 'read_in_full'\n> style thing and in fact churn us more.\n> \n> Ignore this one and I'll look to do it 'right'.\n\nOk, after much hacking about I think I've got something sensible sorted\nout for this.  Following this email are four patches which convert the\nvarious read/write/xread/xwrite users over to xread/read_in_full and\nxwrite/write_in_full as appropriate.  Its pretty invasive as obviously\nI/O is pretty common in an SCM.\n\nnext with this stack passes the builtin test suite.  I additionally used\nthe attached patch to induce severe short read/write semantics.  Before\nthis patch series git was _very_ unhappy, unable to even create a\nrepository.\n\nThis series is against next.\n\n-apw\n\n\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 55456da..931cbed 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -210,6 +210,7 @@ static inline void *xmmap(void *start, size_t length,\n static inline ssize_t xread(int fd, void *buf, size_t len)\n {\n \tssize_t nr;\n+\tif (len > 5) len = 5;\n \twhile (1) {\n \t\tnr = read(fd, buf, len);\n \t\tif ((nr < 0) && (errno == EAGAIN || errno == EINTR))\n@@ -221,6 +222,7 @@ static inline ssize_t xread(int fd, void *buf, size_t len)\n static inline ssize_t xwrite(int fd, const void *buf, size_t len)\n {\n \tssize_t nr;\n+\tif (len > 5) len = 5;\n \twhile (1) {\n \t\tnr = write(fd, buf, len);\n \t\tif ((nr < 0) && (errno == EAGAIN || errno == EINTR))\n"},{"id":"31150","messageId":"25af6e84117845e1ca282192b77e5e67@pinky","threadId":"6233","inReplyTo":"45A2699F.5060100@shadowen.org","subject":"[PATCH 1/4] short i/o: clean up the naming for the write_{in,or}_xxx family","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-08T15:57:52Z","receivedAt":"2007-01-08T15:57:52Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nWe recently introduced a write_in_full() which would either write\nthe specified object or emit an error message and fail.  In order\nto fix the read side we now want to introduce a read_in_full()\nbut without an error emit.  This patch cleans up the naming\nof this family of calls:\n\n1) convert the existing write_or_whine() to write_or_whine_pipe()\n   to better indicate its pipe specific nature,\n2) convert the existing write_in_full() calls to write_or_whine()\n   to better indicate its nature,\n3) introduce a write_in_full() providing a write or fail semantic,\n   and\n4) convert write_or_whine() and write_or_whine_pipe() to use\n   write_in_full().\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\ndiff --git a/cache.h b/cache.h\nindex 36be64e..38a20a8 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -433,9 +433,10 @@ extern char *git_log_output_encoding;\n \n extern int copy_fd(int ifd, int ofd);\n extern void read_or_die(int fd, void *buf, size_t count);\n-extern int write_in_full(int fd, const void *buf, size_t count, const char *);\n+extern int write_in_full(int fd, const void *buf, size_t count);\n extern void write_or_die(int fd, const void *buf, size_t count);\n extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);\n+extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);\n \n /* pager.c */\n extern void setup_pager(void);\ndiff --git a/send-pack.c b/send-pack.c\nindex c195d08..6756264 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -65,14 +65,14 @@ static int pack_objects(int fd, struct ref *refs)\n \t\t\tmemcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);\n \t\t\tbuf[0] = '^';\n \t\t\tbuf[41] = '\\n';\n-\t\t\tif (!write_in_full(pipe_fd[1], buf, 42,\n+\t\t\tif (!write_or_whine(pipe_fd[1], buf, 42,\n \t\t\t\t\t\t\"send-pack: send refs\"))\n \t\t\t\tbreak;\n \t\t}\n \t\tif (!is_null_sha1(refs->new_sha1)) {\n \t\t\tmemcpy(buf, sha1_to_hex(refs->new_sha1), 40);\n \t\t\tbuf[40] = '\\n';\n-\t\t\tif (!write_in_full(pipe_fd[1], buf, 41,\n+\t\t\tif (!write_or_whine(pipe_fd[1], buf, 41,\n \t\t\t\t\t\t\"send-pack: send refs\"))\n \t\t\t\tbreak;\n \t\t}\ndiff --git a/trace.c b/trace.c\nindex 495e5ed..27fef86 100644\n--- a/trace.c\n+++ b/trace.c\n@@ -101,7 +101,7 @@ void trace_printf(const char *format, ...)\n \tnfvasprintf(&trace_str, format, rest);\n \tva_end(rest);\n \n-\twrite_or_whine(fd, trace_str, strlen(trace_str), err_msg);\n+\twrite_or_whine_pipe(fd, trace_str, strlen(trace_str), err_msg);\n \n \tfree(trace_str);\n \n@@ -139,7 +139,7 @@ void trace_argv_printf(const char **argv, int count, const char *format, ...)\n \tstrncpy(trace_str + format_len, argv_str, argv_len);\n \tstrcpy(trace_str + trace_len - 1, \"\\n\");\n \n-\twrite_or_whine(fd, trace_str, trace_len, err_msg);\n+\twrite_or_whine_pipe(fd, trace_str, trace_len, err_msg);\n \n \tfree(argv_str);\n \tfree(format_str);\ndiff --git a/write_or_die.c b/write_or_die.c\nindex 6db1d31..613c0c3 100644\n--- a/write_or_die.c\n+++ b/write_or_die.c\n@@ -35,49 +35,61 @@ void write_or_die(int fd, const void *buf, size_t count)\n \t}\n }\n \n-int write_or_whine(int fd, const void *buf, size_t count, const char *msg)\n+int write_in_full(int fd, const void *buf, size_t count)\n {\n \tconst char *p = buf;\n-\tssize_t written;\n+\tssize_t total = 0;\n+\tssize_t wcount = 0;\n \n \twhile (count > 0) {\n-\t\twritten = xwrite(fd, p, count);\n-\t\tif (written == 0) {\n-\t\t\tfprintf(stderr, \"%s: disk full?\\n\", msg);\n-\t\t\treturn 0;\n-\t\t}\n-\t\telse if (written < 0) {\n-\t\t\tif (errno == EPIPE)\n-\t\t\t\texit(0);\n-\t\t\tfprintf(stderr, \"%s: write error (%s)\\n\",\n-\t\t\t\tmsg, strerror(errno));\n-\t\t\treturn 0;\n+\t\twcount = xwrite(fd, p, count);\n+\t\tif (wcount <= 0) {\n+\t\t\tif (total)\n+\t\t\t\treturn total;\n+\t\t\telse\n+\t\t\t\treturn wcount;\n \t\t}\n-\t\tcount -= written;\n-\t\tp += written;\n+\t\tcount -= wcount;\n+\t\tp += wcount;\n+\t\ttotal += wcount;\n+\t}\n+\n+\treturn wcount;\n+}\n+\n+int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)\n+{\n+\tssize_t written;\n+\n+\twritten = write_in_full(fd, buf, count);\n+\tif (written == 0) {\n+\t\tfprintf(stderr, \"%s: disk full?\\n\", msg);\n+\t\treturn 0;\n+\t}\n+\telse if (written < 0) {\n+\t\tif (errno == EPIPE)\n+\t\t\texit(0);\n+\t\tfprintf(stderr, \"%s: write error (%s)\\n\",\n+\t\t\tmsg, strerror(errno));\n+\t\treturn 0;\n \t}\n \n \treturn 1;\n }\n \n-int write_in_full(int fd, const void *buf, size_t count, const char *msg)\n+int write_or_whine(int fd, const void *buf, size_t count, const char *msg)\n {\n-\tconst char *p = buf;\n \tssize_t written;\n \n-\twhile (count > 0) {\n-\t\twritten = xwrite(fd, p, count);\n-\t\tif (written == 0) {\n-\t\t\tfprintf(stderr, \"%s: disk full?\\n\", msg);\n-\t\t\treturn 0;\n-\t\t}\n-\t\telse if (written < 0) {\n-\t\t\tfprintf(stderr, \"%s: write error (%s)\\n\",\n-\t\t\t\tmsg, strerror(errno));\n-\t\t\treturn 0;\n-\t\t}\n-\t\tcount -= written;\n-\t\tp += written;\n+\twritten = write_in_full(fd, buf, count);\n+\tif (written == 0) {\n+\t\tfprintf(stderr, \"%s: disk full?\\n\", msg);\n+\t\treturn 0;\n+\t}\n+\telse if (written < 0) {\n+\t\tfprintf(stderr, \"%s: write error (%s)\\n\",\n+\t\t\tmsg, strerror(errno));\n+\t\treturn 0;\n \t}\n \n \treturn 1;\n"},{"id":"31151","messageId":"9bcbbe42c4508e6648004084698fca7a@pinky","threadId":"6233","inReplyTo":"45A2699F.5060100@shadowen.org","subject":"[PATCH 2/4] short i/o: fix calls to read to use xread or read_in_full","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-08T15:58:08Z","receivedAt":"2007-01-08T15:58:08Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nWe have a number of badly checked read() calls.  Often we are\nexpecting read() to read exactly the size we requested or fail, this\nfails to handle interrupts or short reads.  Add a read_in_full()\nproviding those semantics.  Otherwise we at a minimum need to check\nfor EINTR and EAGAIN, where this is appropriate use xread().\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex 3b1b1cb..2bfbdb7 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -136,7 +136,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)\n \tif (i < 0)\n \t\tgoto err_ret;\n \tdata = xmalloc(st.st_size + 1);\n-\tif (st.st_size != xread(i, data, st.st_size)) {\n+\tif (st.st_size != read_in_full(i, data, st.st_size)) {\n \t\terror(\"'%s': short read %s\", filename, strerror(errno));\n \t\tclose(i);\n \t\tfree(data);\ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex 11e62fc..ad802fc 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -74,7 +74,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)\n \tchar *content = buffer + RECORDSIZE;\n \tssize_t n;\n \n-\tn = xread(0, buffer, HEADERSIZE);\n+\tn = read_in_full(0, buffer, HEADERSIZE);\n \tif (n < HEADERSIZE)\n \t\tdie(\"git-get-tar-commit-id: read error\");\n \tif (header->typeflag[0] != 'g')\ndiff --git a/builtin-upload-archive.c b/builtin-upload-archive.c\nindex e4156f8..48ae09e 100644\n--- a/builtin-upload-archive.c\n+++ b/builtin-upload-archive.c\n@@ -91,7 +91,7 @@ static void process_input(int child_fd, int band)\n \tchar buf[16384];\n \tssize_t sz = read(child_fd, buf, sizeof(buf));\n \tif (sz < 0) {\n-\t\tif (errno != EINTR)\n+\t\tif (errno != EAGAIN && errno != EINTR)\n \t\t\terror_clnt(\"read error: %s\\n\", strerror(errno));\n \t\treturn;\n \t}\ndiff --git a/cache.h b/cache.h\nindex 38a20a8..a9583ff 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -432,6 +432,7 @@ extern char *git_commit_encoding;\n extern char *git_log_output_encoding;\n \n extern int copy_fd(int ifd, int ofd);\n+extern int read_in_full(int fd, void *buf, size_t count);\n extern void read_or_die(int fd, void *buf, size_t count);\n extern int write_in_full(int fd, const void *buf, size_t count);\n extern void write_or_die(int fd, const void *buf, size_t count);\ndiff --git a/dir.c b/dir.c\nindex 0338d6c..32b57f0 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -142,7 +142,7 @@ static int add_excludes_from_file_1(const char *fname,\n \t\treturn 0;\n \t}\n \tbuf = xmalloc(size+1);\n-\tif (read(fd, buf, size) != size)\n+\tif (read_in_full(fd, buf, size) != size)\n \t\tgoto err;\n \tclose(fd);\n \ndiff --git a/http-fetch.c b/http-fetch.c\nindex 396552d..50a3b00 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -175,7 +175,7 @@ static void start_object_request(struct object_request *obj_req)\n \tprevlocal = open(prevfile, O_RDONLY);\n \tif (prevlocal != -1) {\n \t\tdo {\n-\t\t\tprev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);\n+\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n \t\t\tif (prev_read>0) {\n \t\t\t\tif (fwrite_sha1_file(prev_buf,\n \t\t\t\t\t\t     1,\ndiff --git a/http-push.c b/http-push.c\nindex ecefdfd..acb5c27 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -288,7 +288,7 @@ static void start_fetch_loose(struct transfer_request *request)\n \tprevlocal = open(prevfile, O_RDONLY);\n \tif (prevlocal != -1) {\n \t\tdo {\n-\t\t\tprev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);\n+\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n \t\t\tif (prev_read>0) {\n \t\t\t\tif (fwrite_sha1_file(prev_buf,\n \t\t\t\t\t\t     1,\ndiff --git a/imap-send.c b/imap-send.c\nindex ad91858..8de19e3 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -224,7 +224,7 @@ socket_perror( const char *func, Socket_t *sock, int ret )\n static int\n socket_read( Socket_t *sock, char *buf, int len )\n {\n-\tint n = read( sock->fd, buf, len );\n+\tint n = xread( sock->fd, buf, len );\n \tif (n <= 0) {\n \t\tsocket_perror( \"read\", sock, n );\n \t\tclose( sock->fd );\n@@ -390,7 +390,7 @@ arc4_init( void )\n \t\tfprintf( stderr, \"Fatal: no random number source available.\\n\" );\n \t\texit( 3 );\n \t}\n-\tif (read( fd, dat, 128 ) != 128) {\n+\tif (read_in_full( fd, dat, 128 ) != 128) {\n \t\tfprintf( stderr, \"Fatal: cannot read random number source.\\n\" );\n \t\texit( 3 );\n \t}\ndiff --git a/index-pack.c b/index-pack.c\nindex 5f6d128..e9a5303 100644\n--- a/index-pack.c\n+++ b/index-pack.c\n@@ -638,7 +638,7 @@ static void readjust_pack_header_and_sha1(unsigned char *sha1)\n \t/* Rewrite pack header with updated object number */\n \tif (lseek(output_fd, 0, SEEK_SET) != 0)\n \t\tdie(\"cannot seek back: %s\", strerror(errno));\n-\tif (xread(output_fd, &hdr, sizeof(hdr)) != sizeof(hdr))\n+\tif (read_in_full(output_fd, &hdr, sizeof(hdr)) != sizeof(hdr))\n \t\tdie(\"cannot read pack header back: %s\", strerror(errno));\n \thdr.hdr_entries = htonl(nr_objects);\n \tif (lseek(output_fd, 0, SEEK_SET) != 0)\ndiff --git a/local-fetch.c b/local-fetch.c\nindex 7b6875c..cf99cb7 100644\n--- a/local-fetch.c\n+++ b/local-fetch.c\n@@ -184,7 +184,7 @@ int fetch_ref(char *ref, unsigned char *sha1)\n \t\tfprintf(stderr, \"cannot open %s\\n\", filename);\n \t\treturn -1;\n \t}\n-\tif (read(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {\n+\tif (read_in_full(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {\n \t\tclose(ifd);\n \t\tfprintf(stderr, \"cannot read from %s\\n\", filename);\n \t\treturn -1;\ndiff --git a/path.c b/path.c\nindex 066f621..bb5ee7b 100644\n--- a/path.c\n+++ b/path.c\n@@ -113,7 +113,7 @@ int validate_symref(const char *path)\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n \t\treturn -1;\n-\tlen = read(fd, buffer, sizeof(buffer)-1);\n+\tlen = read_in_full(fd, buffer, sizeof(buffer)-1);\n \tclose(fd);\n \n \t/*\ndiff --git a/refs.c b/refs.c\nindex 5205745..2b69e1e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -284,7 +284,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *\n \t\tfd = open(path, O_RDONLY);\n \t\tif (fd < 0)\n \t\t\treturn NULL;\n-\t\tlen = read(fd, buffer, sizeof(buffer)-1);\n+\t\tlen = read_in_full(fd, buffer, sizeof(buffer)-1);\n \t\tclose(fd);\n \n \t\t/*\ndiff --git a/sha1_file.c b/sha1_file.c\nindex d9622d9..0c9483c 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1869,7 +1869,7 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,\n \t\t\tif (ret != Z_OK)\n \t\t\t\tbreak;\n \t\t}\n-\t\tsize = read(fd, buffer + *bufposn, bufsize - *bufposn);\n+\t\tsize = xread(fd, buffer + *bufposn, bufsize - *bufposn);\n \t\tif (size <= 0) {\n \t\t\tclose(local);\n \t\t\tunlink(tmpfile);\ndiff --git a/ssh-fetch.c b/ssh-fetch.c\nindex b006c5c..72965d6 100644\n--- a/ssh-fetch.c\n+++ b/ssh-fetch.c\n@@ -82,7 +82,7 @@ int fetch(unsigned char *sha1)\n \t\tremote = conn_buf[0];\n \t\tmemmove(conn_buf, conn_buf + 1, --conn_buf_posn);\n \t} else {\n-\t\tif (read(fd_in, &remote, 1) < 1)\n+\t\tif (xread(fd_in, &remote, 1) < 1)\n \t\t\treturn -1;\n \t}\n \t/* fprintf(stderr, \"Got %d\\n\", remote); */\n@@ -99,7 +99,7 @@ static int get_version(void)\n \tchar type = 'v';\n \twrite(fd_out, &type, 1);\n \twrite(fd_out, &local_version, 1);\n-\tif (read(fd_in, &remote_version, 1) < 1) {\n+\tif (xread(fd_in, &remote_version, 1) < 1) {\n \t\treturn error(\"Couldn't read version from remote end\");\n \t}\n \treturn 0;\n@@ -111,10 +111,13 @@ int fetch_ref(char *ref, unsigned char *sha1)\n \tchar type = 'r';\n \twrite(fd_out, &type, 1);\n \twrite(fd_out, ref, strlen(ref) + 1);\n-\tread(fd_in, &remote, 1);\n+\n+\tif (read_in_full(fd_in, &remote, 1) != 1)\n+\t\treturn -1;\n \tif (remote < 0)\n \t\treturn remote;\n-\tread(fd_in, sha1, 20);\n+\tif (read_in_full(fd_in, sha1, 20) != 20)\n+\t\treturn -1;\n \treturn 0;\n }\n \ndiff --git a/ssh-upload.c b/ssh-upload.c\nindex 0b52ae1..2747f96 100644\n--- a/ssh-upload.c\n+++ b/ssh-upload.c\n@@ -21,17 +21,14 @@ static int serve_object(int fd_in, int fd_out) {\n \tssize_t size;\n \tunsigned char sha1[20];\n \tsigned char remote;\n-\tint posn = 0;\n-\tdo {\n-\t\tsize = read(fd_in, sha1 + posn, 20 - posn);\n-\t\tif (size < 0) {\n-\t\t\tperror(\"git-ssh-upload: read \");\n-\t\t\treturn -1;\n-\t\t}\n-\t\tif (!size)\n-\t\t\treturn -1;\n-\t\tposn += size;\n-\t} while (posn < 20);\n+\n+\tsize = read_in_full(fd_in, sha1, 20);\n+\tif (size < 0) {\n+\t\tperror(\"git-ssh-upload: read \");\n+\t\treturn -1;\n+\t}\n+\tif (!size)\n+\t\treturn -1;\n \t\n \tif (verbose)\n \t\tfprintf(stderr, \"Serving %s\\n\", sha1_to_hex(sha1));\n@@ -54,7 +51,7 @@ static int serve_object(int fd_in, int fd_out) {\n \n static int serve_version(int fd_in, int fd_out)\n {\n-\tif (read(fd_in, &remote_version, 1) < 1)\n+\tif (xread(fd_in, &remote_version, 1) < 1)\n \t\treturn -1;\n \twrite(fd_out, &local_version, 1);\n \treturn 0;\n@@ -67,7 +64,7 @@ static int serve_ref(int fd_in, int fd_out)\n \tint posn = 0;\n \tsigned char remote = 0;\n \tdo {\n-\t\tif (read(fd_in, ref + posn, 1) < 1)\n+\t\tif (xread(fd_in, ref + posn, 1) < 1)\n \t\t\treturn -1;\n \t\tposn++;\n \t} while (ref[posn - 1]);\n@@ -89,7 +86,7 @@ static void service(int fd_in, int fd_out) {\n \tchar type;\n \tint retval;\n \tdo {\n-\t\tretval = read(fd_in, &type, 1);\n+\t\tretval = xread(fd_in, &type, 1);\n \t\tif (retval < 1) {\n \t\t\tif (retval < 0)\n \t\t\t\tperror(\"git-ssh-upload: read \");\ndiff --git a/upload-pack.c b/upload-pack.c\nindex c568ef0..03a4156 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -242,7 +242,7 @@ static void create_pack_file(void)\n \t\t\t\t\t*cp++ = buffered;\n \t\t\t\t\toutsz++;\n \t\t\t\t}\n-\t\t\t\tsz = read(pu_pipe[0], cp,\n+\t\t\t\tsz = xread(pu_pipe[0], cp,\n \t\t\t\t\t  sizeof(data) - outsz);\n \t\t\t\tif (0 < sz)\n \t\t\t\t\t\t;\n@@ -267,7 +267,7 @@ static void create_pack_file(void)\n \t\t\t\t/* Status ready; we ship that in the side-band\n \t\t\t\t * or dump to the standard error.\n \t\t\t\t */\n-\t\t\t\tsz = read(pe_pipe[0], progress,\n+\t\t\t\tsz = xread(pe_pipe[0], progress,\n \t\t\t\t\t  sizeof(progress));\n \t\t\t\tif (0 < sz)\n \t\t\t\t\tsend_client_data(2, progress, sz);\ndiff --git a/write_or_die.c b/write_or_die.c\nindex 613c0c3..e7f8263 100644\n--- a/write_or_die.c\n+++ b/write_or_die.c\n@@ -1,19 +1,36 @@\n #include \"cache.h\"\n \n-void read_or_die(int fd, void *buf, size_t count)\n+int read_in_full(int fd, void *buf, size_t count)\n {\n \tchar *p = buf;\n-\tssize_t loaded;\n+\tssize_t total = 0;\n+\tssize_t loaded = 0;\n \n \twhile (count > 0) {\n \t\tloaded = xread(fd, p, count);\n-\t\tif (loaded == 0)\n-\t\t\tdie(\"unexpected end of file\");\n-\t\telse if (loaded < 0)\n-\t\t\tdie(\"read error (%s)\", strerror(errno));\n+\t\tif (loaded <= 0) {\n+\t\t\tif (total)\n+\t\t\t\treturn total;\n+\t\t\telse\n+\t\t\t\treturn loaded;\n+\t\t}\n \t\tcount -= loaded;\n \t\tp += loaded;\n+\t\ttotal += loaded;\n \t}\n+\n+\treturn total;\n+}\n+\n+void read_or_die(int fd, void *buf, size_t count)\n+{\n+\tssize_t loaded;\n+\n+\tloaded = read_in_full(fd, buf, count);\n+\tif (loaded == 0)\n+\t\tdie(\"unexpected end of file\");\n+\telse if (loaded < 0)\n+\t\tdie(\"read error (%s)\", strerror(errno));\n }\n \n void write_or_die(int fd, const void *buf, size_t count)\n"},{"id":"31152","messageId":"9120c8418678fa5fe59f86abc7fb86b0@pinky","threadId":"6233","inReplyTo":"45A2699F.5060100@shadowen.org","subject":"[PATCH 3/4] short i/o: fix calls to write to use xwrite or write_in_full","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-08T15:58:23Z","receivedAt":"2007-01-08T15:58:23Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nWe have a number of badly checked write() calls.  Often we are\nexpecting write() to write exactly the size we requested or fail,\nthis fails to handle interrupts or short writes.  Switch to using\nthe new write_in_full().  Otherwise we at a minimum need to check\nfor EINTR and EAGAIN, where this is appropriate use xwrite().\n\nNote, the changes to config handling are much larger and handled\nin the next patch in the sequence.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\ndiff --git a/builtin-rerere.c b/builtin-rerere.c\nindex 079c0bd..318d959 100644\n--- a/builtin-rerere.c\n+++ b/builtin-rerere.c\n@@ -51,9 +51,11 @@ static int write_rr(struct path_list *rr, int out_fd)\n \tint i;\n \tfor (i = 0; i < rr->nr; i++) {\n \t\tconst char *path = rr->items[i].path;\n-\t\twrite(out_fd, rr->items[i].util, 40);\n-\t\twrite(out_fd, \"\\t\", 1);\n-\t\twrite(out_fd, path, strlen(path) + 1);\n+\t\tint length = strlen(path) + 1;\n+\t\tif (write_in_full(out_fd, rr->items[i].util, 40) != 40 ||\n+\t\t    write_in_full(out_fd, \"\\t\", 1) != 1 ||\n+\t\t    write_in_full(out_fd, path, length) != length)\n+\t\t\tdie(\"unable to write rerere record\");\n \t}\n \tclose(out_fd);\n \treturn commit_lock_file(&write_lock);\n@@ -244,7 +246,8 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)\n {\n \tint i;\n \tfor (i = 0; i < nbuf; i++)\n-\t\twrite(1, ptr[i].ptr, ptr[i].size);\n+\t\tif (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)\n+\t\t\treturn -1;\n \treturn 0;\n }\n \ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex ad802fc..8055dda 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -82,7 +82,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)\n \tif (memcmp(content, \"52 comment=\", 11))\n \t\treturn 1;\n \n-\tn = xwrite(1, content + 11, 41);\n+\tn = write_in_full(1, content + 11, 41);\n \tif (n < 41)\n \t\tdie(\"git-get-tar-commit-id: write error\");\n \ndiff --git a/commit.c b/commit.c\nindex 2a58175..9ce45ce 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -249,8 +249,10 @@ int write_shallow_commits(int fd, int use_pack_protocol)\n \t\t\tif (use_pack_protocol)\n \t\t\t\tpacket_write(fd, \"shallow %s\", hex);\n \t\t\telse {\n-\t\t\t\twrite(fd, hex,  40);\n-\t\t\t\twrite(fd, \"\\n\", 1);\n+\t\t\t\tif (write_in_full(fd, hex,  40) != 40)\n+\t\t\t\t\tbreak;\n+\t\t\t\tif (write_in_full(fd, \"\\n\", 1) != 1)\n+\t\t\t\t\tbreak;\n \t\t\t}\n \t\t}\n \treturn count;\ndiff --git a/daemon.c b/daemon.c\nindex b129b83..f039534 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -102,7 +102,7 @@ static void logreport(int priority, const char *err, va_list params)\n \tbuf[buflen++] = '\\n';\n \tbuf[buflen] = '\\0';\n \n-\twrite(2, buf, buflen);\n+\twrite_in_full(2, buf, buflen);\n }\n \n static void logerror(const char *err, ...)\ndiff --git a/diff.c b/diff.c\nindex 1fee15a..f11a633 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1403,7 +1403,7 @@ static void prep_temp_blob(struct diff_tempfile *temp,\n \tfd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, \".diff_XXXXXX\");\n \tif (fd < 0)\n \t\tdie(\"unable to create temp-file\");\n-\tif (write(fd, blob, size) != size)\n+\tif (write_in_full(fd, blob, size) != size)\n \t\tdie(\"unable to write temp-file\");\n \tclose(fd);\n \ttemp->name = temp->tmp_path;\ndiff --git a/entry.c b/entry.c\nindex 88df713..0ebf0f0 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -89,7 +89,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat\n \t\t\treturn error(\"git-checkout-index: unable to create file %s (%s)\",\n \t\t\t\tpath, strerror(errno));\n \t\t}\n-\t\twrote = write(fd, new, size);\n+\t\twrote = write_in_full(fd, new, size);\n \t\tclose(fd);\n \t\tfree(new);\n \t\tif (wrote != size)\n@@ -104,7 +104,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat\n \t\t\t\treturn error(\"git-checkout-index: unable to create \"\n \t\t\t\t\t\t \"file %s (%s)\", path, strerror(errno));\n \t\t\t}\n-\t\t\twrote = write(fd, new, size);\n+\t\t\twrote = write_in_full(fd, new, size);\n \t\t\tclose(fd);\n \t\t\tfree(new);\n \t\t\tif (wrote != size)\ndiff --git a/http-fetch.c b/http-fetch.c\nindex 50a3b00..fe8cd7b 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -71,7 +71,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n \tint posn = 0;\n \tstruct object_request *obj_req = (struct object_request *)data;\n \tdo {\n-\t\tssize_t retval = write(obj_req->local,\n+\t\tssize_t retval = xwrite(obj_req->local,\n \t\t\t\t       (char *) ptr + posn, size - posn);\n \t\tif (retval < 0)\n \t\t\treturn posn;\ndiff --git a/http-push.c b/http-push.c\nindex acb5c27..7e73eac 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -195,7 +195,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n \tint posn = 0;\n \tstruct transfer_request *request = (struct transfer_request *)data;\n \tdo {\n-\t\tssize_t retval = write(request->local_fileno,\n+\t\tssize_t retval = xwrite(request->local_fileno,\n \t\t\t\t       (char *) ptr + posn, size - posn);\n \t\tif (retval < 0)\n \t\t\treturn posn;\ndiff --git a/imap-send.c b/imap-send.c\nindex 8de19e3..3eaf025 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -236,7 +236,7 @@ socket_read( Socket_t *sock, char *buf, int len )\n static int\n socket_write( Socket_t *sock, const char *buf, int len )\n {\n-\tint n = write( sock->fd, buf, len );\n+\tint n = write_in_full( sock->fd, buf, len );\n \tif (n != len) {\n \t\tsocket_perror( \"write\", sock, n );\n \t\tclose( sock->fd );\ndiff --git a/index-pack.c b/index-pack.c\nindex e9a5303..8d10d6b 100644\n--- a/index-pack.c\n+++ b/index-pack.c\n@@ -814,7 +814,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,\n \t\tchar buf[48];\n \t\tint len = snprintf(buf, sizeof(buf), \"%s\\t%s\\n\",\n \t\t\t\t   report, sha1_to_hex(sha1));\n-\t\txwrite(1, buf, len);\n+\t\twrite_in_full(1, buf, len);\n \n \t\t/*\n \t\t * Let's just mimic git-unpack-objects here and write\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex bac16f5..87a27e0 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -517,7 +517,7 @@ static int mkdir_p(const char *path, unsigned long mode)\n static void flush_buffer(int fd, const char *buf, unsigned long size)\n {\n \twhile (size > 0) {\n-\t\tlong ret = xwrite(fd, buf, size);\n+\t\tlong ret = write_in_full(fd, buf, size);\n \t\tif (ret < 0) {\n \t\t\t/* Ignore epipe */\n \t\t\tif (errno == EPIPE)\ndiff --git a/read-cache.c b/read-cache.c\nindex 29cf9ab..8ecd826 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -870,7 +870,7 @@ static int ce_write_flush(SHA_CTX *context, int fd)\n \tunsigned int buffered = write_buffer_len;\n \tif (buffered) {\n \t\tSHA1_Update(context, write_buffer, buffered);\n-\t\tif (write(fd, write_buffer, buffered) != buffered)\n+\t\tif (write_in_full(fd, write_buffer, buffered) != buffered)\n \t\t\treturn -1;\n \t\twrite_buffer_len = 0;\n \t}\n@@ -919,7 +919,7 @@ static int ce_flush(SHA_CTX *context, int fd)\n \n \t/* Flush first if not enough space for SHA1 signature */\n \tif (left + 20 > WRITE_BUFFER_SIZE) {\n-\t\tif (write(fd, write_buffer, left) != left)\n+\t\tif (write_in_full(fd, write_buffer, left) != left)\n \t\t\treturn -1;\n \t\tleft = 0;\n \t}\n@@ -927,7 +927,7 @@ static int ce_flush(SHA_CTX *context, int fd)\n \t/* Append the SHA1 signature at the end */\n \tSHA1_Final(write_buffer + left, context);\n \tleft += 20;\n-\treturn (write(fd, write_buffer, left) != left) ? -1 : 0;\n+\treturn (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;\n }\n \n static void ce_smudge_racily_clean_entry(struct cache_entry *ce)\ndiff --git a/refs.c b/refs.c\nindex 2b69e1e..4d6fad8 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -332,7 +332,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master)\n \t}\n \tlockpath = mkpath(\"%s.lock\", git_HEAD);\n \tfd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);\t\n-\twritten = write(fd, ref, len);\n+\twritten = write_in_full(fd, ref, len);\n \tclose(fd);\n \tif (written != len) {\n \t\tunlink(lockpath);\n@@ -968,7 +968,7 @@ static int log_ref_write(struct ref_lock *lock,\n \t\t\tsha1_to_hex(sha1),\n \t\t\tcommitter);\n \t}\n-\twritten = len <= maxlen ? write(logfd, logrec, len) : -1;\n+\twritten = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;\n \tfree(logrec);\n \tclose(logfd);\n \tif (written != len)\n@@ -987,8 +987,8 @@ int write_ref_sha1(struct ref_lock *lock,\n \t\tunlock_ref(lock);\n \t\treturn 0;\n \t}\n-\tif (write(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||\n-\t    write(lock->lock_fd, &term, 1) != 1\n+\tif (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||\n+\t    write_in_full(lock->lock_fd, &term, 1) != 1\n \t\t|| close(lock->lock_fd) < 0) {\n \t\terror(\"Couldn't write %s\", lock->lk->filename);\n \t\tunlock_ref(lock);\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 0c9483c..095a7e1 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1611,20 +1611,13 @@ int move_temp_to_file(const char *tmpfile, const char *filename)\n \n static int write_buffer(int fd, const void *buf, size_t len)\n {\n-\twhile (len) {\n-\t\tssize_t size;\n+\tssize_t size;\n \n-\t\tsize = write(fd, buf, len);\n-\t\tif (!size)\n-\t\t\treturn error(\"file write: disk full\");\n-\t\tif (size < 0) {\n-\t\t\tif (errno == EINTR || errno == EAGAIN)\n-\t\t\t\tcontinue;\n-\t\t\treturn error(\"file write error (%s)\", strerror(errno));\n-\t\t}\n-\t\tlen -= size;\n-\t\tbuf = (char *) buf + size;\n-\t}\n+\tsize = write_in_full(fd, buf, len);\n+\tif (!size)\n+\t\treturn error(\"file write: disk full\");\n+\tif (size < 0)\n+\t\treturn error(\"file write error (%s)\", strerror(errno));\n \treturn 0;\n }\n \ndiff --git a/ssh-fetch.c b/ssh-fetch.c\nindex 72965d6..4c172b6 100644\n--- a/ssh-fetch.c\n+++ b/ssh-fetch.c\n@@ -20,22 +20,6 @@ static int fd_out;\n static unsigned char remote_version;\n static unsigned char local_version = 1;\n \n-static ssize_t force_write(int fd, void *buffer, size_t length)\n-{\n-\tssize_t ret = 0;\n-\twhile (ret < length) {\n-\t\tssize_t size = write(fd, (char *) buffer + ret, length - ret);\n-\t\tif (size < 0) {\n-\t\t\treturn size;\n-\t\t}\n-\t\tif (size == 0) {\n-\t\t\treturn ret;\n-\t\t}\n-\t\tret += size;\n-\t}\n-\treturn ret;\n-}\n-\n static int prefetches;\n \n static struct object_list *in_transit;\n@@ -53,8 +37,9 @@ void prefetch(unsigned char *sha1)\n \tnode->item = lookup_unknown_object(sha1);\n \t*end_of_transit = node;\n \tend_of_transit = &node->next;\n-\tforce_write(fd_out, &type, 1);\n-\tforce_write(fd_out, sha1, 20);\n+\t/* XXX: what if these writes fail? */\n+\twrite_in_full(fd_out, &type, 1);\n+\twrite_in_full(fd_out, sha1, 20);\n \tprefetches++;\n }\n \n@@ -97,8 +82,10 @@ int fetch(unsigned char *sha1)\n static int get_version(void)\n {\n \tchar type = 'v';\n-\twrite(fd_out, &type, 1);\n-\twrite(fd_out, &local_version, 1);\n+\tif (write_in_full(fd_out, &type, 1) != 1 ||\n+\t    write_in_full(fd_out, &local_version, 1)) {\n+\t\treturn error(\"Couldn't request version from remote end\");\n+\t}\n \tif (xread(fd_in, &remote_version, 1) < 1) {\n \t\treturn error(\"Couldn't read version from remote end\");\n \t}\n@@ -109,8 +96,10 @@ int fetch_ref(char *ref, unsigned char *sha1)\n {\n \tsigned char remote;\n \tchar type = 'r';\n-\twrite(fd_out, &type, 1);\n-\twrite(fd_out, ref, strlen(ref) + 1);\n+\tint length = strlen(ref) + 1;\n+\tif (write_in_full(fd_out, &type, 1) != 1 ||\n+\t    write_in_full(fd_out, ref, length) != length)\n+\t\treturn -1;\n \n \tif (read_in_full(fd_in, &remote, 1) != 1)\n \t\treturn -1;\ndiff --git a/ssh-upload.c b/ssh-upload.c\nindex 2747f96..07e61e5 100644\n--- a/ssh-upload.c\n+++ b/ssh-upload.c\n@@ -41,7 +41,8 @@ static int serve_object(int fd_in, int fd_out) {\n \t\tremote = -1;\n \t}\n \t\n-\twrite(fd_out, &remote, 1);\n+\tif (write_in_full(fd_out, &remote, 1) != 1)\n+\t\treturn 0;\n \t\n \tif (remote < 0)\n \t\treturn 0;\n@@ -53,7 +54,7 @@ static int serve_version(int fd_in, int fd_out)\n {\n \tif (xread(fd_in, &remote_version, 1) < 1)\n \t\treturn -1;\n-\twrite(fd_out, &local_version, 1);\n+\twrite_in_full(fd_out, &local_version, 1);\n \treturn 0;\n }\n \n@@ -74,10 +75,11 @@ static int serve_ref(int fd_in, int fd_out)\n \n \tif (get_ref_sha1(ref, sha1))\n \t\tremote = -1;\n-\twrite(fd_out, &remote, 1);\n+\tif (write_in_full(fd_out, &remote, 1) != 1)\n+\t\treturn 0;\n \tif (remote)\n \t\treturn 0;\n-\twrite(fd_out, sha1, 20);\n+\twrite_in_full(fd_out, sha1, 20);\n         return 0;\n }\n \ndiff --git a/test-delta.c b/test-delta.c\nindex 795aa08..16595ef 100644\n--- a/test-delta.c\n+++ b/test-delta.c\n@@ -68,7 +68,7 @@ int main(int argc, char *argv[])\n \t}\n \n \tfd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);\n-\tif (fd < 0 || write(fd, out_buf, out_size) != out_size) {\n+\tif (fd < 0 || write_in_full(fd, out_buf, out_size) != out_size) {\n \t\tperror(argv[4]);\n \t\treturn 1;\n \t}\ndiff --git a/unpack-file.c b/unpack-file.c\nindex ccddf1d..d24acc2 100644\n--- a/unpack-file.c\n+++ b/unpack-file.c\n@@ -17,7 +17,7 @@ static char *create_temp_file(unsigned char *sha1)\n \tfd = mkstemp(path);\n \tif (fd < 0)\n \t\tdie(\"unable to create temp-file\");\n-\tif (write(fd, buf, size) != size)\n+\tif (write_in_full(fd, buf, size) != size)\n \t\tdie(\"unable to write temp-file\");\n \tclose(fd);\n \treturn path;\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 03a4156..3a466c6 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -55,6 +55,7 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)\n \t\t/* emergency quit */\n \t\tfd = 2;\n \tif (fd == 2) {\n+\t\t/* XXX: are we happy to lose stuff here? */\n \t\txwrite(fd, data, sz);\n \t\treturn sz;\n \t}\ndiff --git a/write_or_die.c b/write_or_die.c\nindex e7f8263..a119e1d 100644\n--- a/write_or_die.c\n+++ b/write_or_die.c\n@@ -33,45 +33,40 @@ void read_or_die(int fd, void *buf, size_t count)\n \t\tdie(\"read error (%s)\", strerror(errno));\n }\n \n-void write_or_die(int fd, const void *buf, size_t count)\n+int write_in_full(int fd, const void *buf, size_t count)\n {\n \tconst char *p = buf;\n-\tssize_t written;\n+\tssize_t total = 0;\n+\tssize_t written = 0;\n \n \twhile (count > 0) {\n \t\twritten = xwrite(fd, p, count);\n-\t\tif (written == 0)\n-\t\t\tdie(\"disk full?\");\n-\t\telse if (written < 0) {\n-\t\t\tif (errno == EPIPE)\n-\t\t\t\texit(0);\n-\t\t\tdie(\"write error (%s)\", strerror(errno));\n+\t\tif (written <= 0) {\n+\t\t\tif (total)\n+\t\t\t\treturn total;\n+\t\t\telse\n+\t\t\t\treturn written;\n \t\t}\n \t\tcount -= written;\n \t\tp += written;\n+\t\ttotal += written;\n \t}\n+\n+\treturn total;\n }\n \n-int write_in_full(int fd, const void *buf, size_t count)\n+void write_or_die(int fd, const void *buf, size_t count)\n {\n-\tconst char *p = buf;\n-\tssize_t total = 0;\n-\tssize_t wcount = 0;\n+\tssize_t written;\n \n-\twhile (count > 0) {\n-\t\twcount = xwrite(fd, p, count);\n-\t\tif (wcount <= 0) {\n-\t\t\tif (total)\n-\t\t\t\treturn total;\n-\t\t\telse\n-\t\t\t\treturn wcount;\n-\t\t}\n-\t\tcount -= wcount;\n-\t\tp += wcount;\n-\t\ttotal += wcount;\n+\twritten = write_in_full(fd, buf, count);\n+\tif (written == 0)\n+\t\tdie(\"disk full?\");\n+\telse if (written < 0) {\n+\t\tif (errno == EPIPE)\n+\t\t\texit(0);\n+\t\tdie(\"write error (%s)\", strerror(errno));\n \t}\n-\n-\treturn wcount;\n }\n \n int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)\n"},{"id":"31153","messageId":"260688736d18821c694cf54e11de60e7@pinky","threadId":"6233","inReplyTo":"45A2699F.5060100@shadowen.org","subject":"[PATCH 4/4] short i/o: fix config updates to use write_in_full","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-08T15:58:38Z","receivedAt":"2007-01-08T15:58:38Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nWe need to check that the writes we perform during the update of\nthe users configuration work.  Convert to using write_in_full().\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\ndiff --git a/config.c b/config.c\nindex 5cbd130..2c9d07c 100644\n--- a/config.c\n+++ b/config.c\n@@ -464,7 +464,15 @@ static int store_aux(const char* key, const char* value)\n \treturn 0;\n }\n \n-static void store_write_section(int fd, const char* key)\n+static int write_error()\n+{\n+\tfprintf(stderr, \"Failed to write new configuration file\\n\");\n+\t\n+\t/* Same error code as \"failed to rename\". */\n+\treturn 4;\n+}\n+\n+static int store_write_section(int fd, const char* key)\n {\n \tconst char *dot = strchr(key, '.');\n \tint len1 = store.baselen, len2 = -1;\n@@ -478,37 +486,60 @@ static void store_write_section(int fd, const char* key)\n \t\t}\n \t}\n \n-\twrite(fd, \"[\", 1);\n-\twrite(fd, key, len1);\n+\tif (write_in_full(fd, \"[\", 1) != 1 ||\n+\t    write_in_full(fd, key, len1) != len1)\n+\t\treturn 0;\n \tif (len2 >= 0) {\n-\t\twrite(fd, \" \\\"\", 2);\n+\t\tif (write_in_full(fd, \" \\\"\", 2) != 2)\n+\t\t\treturn 0;\n \t\twhile (--len2 >= 0) {\n \t\t\tunsigned char c = *++dot;\n \t\t\tif (c == '\"')\n-\t\t\t\twrite(fd, \"\\\\\", 1);\n-\t\t\twrite(fd, &c, 1);\n+\t\t\t\tif (write_in_full(fd, \"\\\\\", 1) != 1)\n+\t\t\t\t\treturn 0;\n+\t\t\tif (write_in_full(fd, &c, 1) != 1)\n+\t\t\t\treturn 0;\n \t\t}\n-\t\twrite(fd, \"\\\"\", 1);\n+\t\tif (write_in_full(fd, \"\\\"\", 1) != 1)\n+\t\t\treturn 0;\n \t}\n-\twrite(fd, \"]\\n\", 2);\n+\tif (write_in_full(fd, \"]\\n\", 2) != 2)\n+\t\treturn 0;\n+\n+\treturn 1;\n }\n \n-static void store_write_pair(int fd, const char* key, const char* value)\n+static int store_write_pair(int fd, const char* key, const char* value)\n {\n \tint i;\n+\tint length = strlen(key+store.baselen+1);\n \n-\twrite(fd, \"\\t\", 1);\n-\twrite(fd, key+store.baselen+1,\n-\t\tstrlen(key+store.baselen+1));\n-\twrite(fd, \" = \", 3);\n+\tif (write_in_full(fd, \"\\t\", 1) != 1 ||\n+\t    write_in_full(fd, key+store.baselen+1, length) != length ||\n+\t    write_in_full(fd, \" = \", 3) != 3)\n+\t\treturn 0;\n \tfor (i = 0; value[i]; i++)\n \t\tswitch (value[i]) {\n-\t\tcase '\\n': write(fd, \"\\\\n\", 2); break;\n-\t\tcase '\\t': write(fd, \"\\\\t\", 2); break;\n-\t\tcase '\"': case '\\\\': write(fd, \"\\\\\", 1);\n-\t\tdefault: write(fd, value+i, 1);\n-\t}\n-\twrite(fd, \"\\n\", 1);\n+\t\tcase '\\n':\n+\t\t\tif (write_in_full(fd, \"\\\\n\", 2) != 2)\n+\t\t\t\treturn 0;\n+\t\t\tbreak;\n+\t\tcase '\\t':\n+\t\t\tif (write_in_full(fd, \"\\\\t\", 2) != 2)\n+\t\t\t\treturn 0;\n+\t\t\tbreak;\n+\t\tcase '\"':\n+\t\tcase '\\\\':\n+\t\t\tif (write_in_full(fd, \"\\\\\", 1) != 1)\n+\t\t\t\treturn 0;\n+\t\tdefault:\n+\t\t\tif (write_in_full(fd, value+i, 1) != 1)\n+\t\t\t\treturn 0;\n+\t\t\tbreak;\n+\t\t}\n+\tif (write_in_full(fd, \"\\n\", 1) != 1)\n+\t\treturn 0;\n+\treturn 1;\n }\n \n static int find_beginning_of_line(const char* contents, int size,\n@@ -648,8 +679,11 @@ int git_config_set_multivar(const char* key, const char* value,\n \t\t}\n \n \t\tstore.key = (char*)key;\n-\t\tstore_write_section(fd, key);\n-\t\tstore_write_pair(fd, key, value);\n+\t\tif (!store_write_section(fd, key) ||\n+\t\t    !store_write_pair(fd, key, value)) {\n+\t\t\tret = write_error();\n+\t\t\tgoto out_free;\n+\t\t}\n \t} else{\n \t\tstruct stat st;\n \t\tchar* contents;\n@@ -729,10 +763,10 @@ int git_config_set_multivar(const char* key, const char* value,\n \n \t\t\t/* write the first part of the config */\n \t\t\tif (copy_end > copy_begin) {\n-\t\t\t\twrite(fd, contents + copy_begin,\n+\t\t\t\twrite_in_full(fd, contents + copy_begin,\n \t\t\t\tcopy_end - copy_begin);\n \t\t\t\tif (new_line)\n-\t\t\t\t\twrite(fd, \"\\n\", 1);\n+\t\t\t\t\twrite_in_full(fd, \"\\n\", 1);\n \t\t\t}\n \t\t\tcopy_begin = store.offset[i];\n \t\t}\n@@ -740,13 +774,19 @@ int git_config_set_multivar(const char* key, const char* value,\n \t\t/* write the pair (value == NULL means unset) */\n \t\tif (value != NULL) {\n \t\t\tif (store.state == START)\n-\t\t\t\tstore_write_section(fd, key);\n-\t\t\tstore_write_pair(fd, key, value);\n+\t\t\t\tif (!store_write_section(fd, key)) {\n+\t\t\t\t\tret = write_error();\n+\t\t\t\t\tgoto out_free;\n+\t\t\t\t}\n+\t\t\tif (!store_write_pair(fd, key, value)) {\n+\t\t\t\tret = write_error();\n+\t\t\t\tgoto out_free;\n+\t\t\t}\n \t\t}\n \n \t\t/* write the rest of the config */\n \t\tif (copy_begin < st.st_size)\n-\t\t\twrite(fd, contents + copy_begin,\n+\t\t\twrite_in_full(fd, contents + copy_begin,\n \t\t\t\tst.st_size - copy_begin);\n \n \t\tmunmap(contents, st.st_size);\n@@ -800,6 +840,7 @@ int git_config_rename_section(const char *old_name, const char *new_name)\n \n \twhile (fgets(buf, sizeof(buf), config_file)) {\n \t\tint i;\n+\t\tint length;\n \t\tfor (i = 0; buf[i] && isspace(buf[i]); i++)\n \t\t\t; /* do nothing */\n \t\tif (buf[i] == '[') {\n@@ -830,15 +871,22 @@ int git_config_rename_section(const char *old_name, const char *new_name)\n \t\t\t\t/* old_name matches */\n \t\t\t\tret++;\n \t\t\t\tstore.baselen = strlen(new_name);\n-\t\t\t\tstore_write_section(out_fd, new_name);\n+\t\t\t\tif (!store_write_section(out_fd, new_name)) {\n+\t\t\t\t\tret = write_error();\n+\t\t\t\t\tgoto out;\n+\t\t\t\t}\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\twrite(out_fd, buf, strlen(buf));\n+\t\tlength = strlen(buf);\n+\t\tif (write_in_full(out_fd, buf, length) != length) {\n+\t\t\tret = write_error();\n+\t\t\tgoto out;\n+\t\t}\n \t}\n \tfclose(config_file);\n \tif (close(out_fd) || commit_lock_file(lock) < 0)\n-\t\tret = error(\"Cannot commit config file!\");\n+\t\t\tret = error(\"Cannot commit config file!\");\n  out:\n \tfree(config_filename);\n \treturn ret;\n"},{"id":"31158","messageId":"7vk5zxwa3d.fsf@assigned-by-dhcp.cox.net","threadId":"6233","inReplyTo":"45A2699F.5060100@shadowen.org","subject":"Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-01-08T20:13:26Z","receivedAt":"2007-01-08T20:13:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks.  Will queue in 'next' to cook for a few days with the\nintent to have it in v1.5.0-rc1.\n"},{"id":"31497","messageId":"20070111214340.GA25445@mayonaise.dyndns.org","threadId":"6233","inReplyTo":"45A2699F.5060100@shadowen.org","subject":"[PATCH] Avoid errors and warnings when attempting to do I/O on zero bytes","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2007-01-11T21:43:40Z","receivedAt":"2007-01-11T21:43:40Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Unfortunately, while {read,write}_in_full do take into account\nzero-sized reads/writes; their die and whine variants do not.\n\nI have a repository where there are zero-sized files in\nthe history that was triggering these things.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n sha1_file.c    |    2 ++\n write_or_die.c |    8 ++++++++\n 2 files changed, 10 insertions(+), 0 deletions(-)\n\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 53e25f2..18dd89b 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1620,6 +1620,8 @@ static int write_buffer(int fd, const void *buf, size_t len)\n {\n \tssize_t size;\n \n+\tif (!len)\n+\t\treturn 0;\n \tsize = write_in_full(fd, buf, len);\n \tif (!size)\n \t\treturn error(\"file write: disk full\");\ndiff --git a/write_or_die.c b/write_or_die.c\nindex a119e1d..700ccd1 100644\n--- a/write_or_die.c\n+++ b/write_or_die.c\n@@ -26,6 +26,8 @@ void read_or_die(int fd, void *buf, size_t count)\n {\n \tssize_t loaded;\n \n+\tif (!count)\n+\t\treturn;\n \tloaded = read_in_full(fd, buf, count);\n \tif (loaded == 0)\n \t\tdie(\"unexpected end of file\");\n@@ -59,6 +61,8 @@ void write_or_die(int fd, const void *buf, size_t count)\n {\n \tssize_t written;\n \n+\tif (!count)\n+\t\treturn;\n \twritten = write_in_full(fd, buf, count);\n \tif (written == 0)\n \t\tdie(\"disk full?\");\n@@ -73,6 +77,8 @@ int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)\n {\n \tssize_t written;\n \n+\tif (!count)\n+\t\treturn 1;\n \twritten = write_in_full(fd, buf, count);\n \tif (written == 0) {\n \t\tfprintf(stderr, \"%s: disk full?\\n\", msg);\n@@ -93,6 +99,8 @@ int write_or_whine(int fd, const void *buf, size_t count, const char *msg)\n {\n \tssize_t written;\n \n+\tif (!count)\n+\t\treturn 1;\n \twritten = write_in_full(fd, buf, count);\n \tif (written == 0) {\n \t\tfprintf(stderr, \"%s: disk full?\\n\", msg);\n-- \nEric Wong\n"}]}