* [PATCH] use xread where we are not checking for EAGAIN/EINTR
@ 2007-01-05 10:54 Andy Whitcroft
2007-01-05 11:19 ` Junio C Hamano
0 siblings, 1 reply; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-05 10:54 UTC (permalink / raw)
To: git
We have xread() to handle those OS's which will return EAGAIN or
EINTR when the read is interrupted. We should use this where we
are not otherwise handling such errors.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
We have an xread() wrapper to help us with those nasty
interrupt returns and yet we fail to use it consistently.
This patch updates those plain read()'s which do not
have any handling for errors, or which treat those errors
as user visible fatal errors.
This feels right to me, but perhaps there is some good
reason that things are done this way ... if so could
someone elighten me.
If this is a sensible change, then I'll have a look at
the write side.
---
diff --git a/dir.c b/dir.c
index 0338d6c..8fe0865 100644
--- a/dir.c
+++ b/dir.c
@@ -142,7 +142,7 @@ static int add_excludes_from_file_1(const char *fname,
return 0;
}
buf = xmalloc(size+1);
- if (read(fd, buf, size) != size)
+ if (xread(fd, buf, size) != size)
goto err;
close(fd);
diff --git a/http-fetch.c b/http-fetch.c
index 396552d..50a3b00 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -175,7 +175,7 @@ static void start_object_request(struct object_request *obj_req)
prevlocal = open(prevfile, O_RDONLY);
if (prevlocal != -1) {
do {
- prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+ prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
if (prev_read>0) {
if (fwrite_sha1_file(prev_buf,
1,
diff --git a/http-push.c b/http-push.c
index ecefdfd..acb5c27 100644
--- a/http-push.c
+++ b/http-push.c
@@ -288,7 +288,7 @@ static void start_fetch_loose(struct transfer_request *request)
prevlocal = open(prevfile, O_RDONLY);
if (prevlocal != -1) {
do {
- prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+ prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
if (prev_read>0) {
if (fwrite_sha1_file(prev_buf,
1,
diff --git a/imap-send.c b/imap-send.c
index ad91858..3f1e542 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -224,7 +224,7 @@ socket_perror( const char *func, Socket_t *sock, int ret )
static int
socket_read( Socket_t *sock, char *buf, int len )
{
- int n = read( sock->fd, buf, len );
+ int n = xread( sock->fd, buf, len );
if (n <= 0) {
socket_perror( "read", sock, n );
close( sock->fd );
@@ -390,7 +390,7 @@ arc4_init( void )
fprintf( stderr, "Fatal: no random number source available.\n" );
exit( 3 );
}
- if (read( fd, dat, 128 ) != 128) {
+ if (xread( fd, dat, 128 ) != 128) {
fprintf( stderr, "Fatal: cannot read random number source.\n" );
exit( 3 );
}
diff --git a/local-fetch.c b/local-fetch.c
index 7b6875c..21bcf75 100644
--- a/local-fetch.c
+++ b/local-fetch.c
@@ -184,7 +184,7 @@ int fetch_ref(char *ref, unsigned char *sha1)
fprintf(stderr, "cannot open %s\n", filename);
return -1;
}
- if (read(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {
+ if (xread(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {
close(ifd);
fprintf(stderr, "cannot read from %s\n", filename);
return -1;
diff --git a/path.c b/path.c
index 066f621..f6f9cfd 100644
--- a/path.c
+++ b/path.c
@@ -113,7 +113,7 @@ int validate_symref(const char *path)
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
- len = read(fd, buffer, sizeof(buffer)-1);
+ len = xread(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
diff --git a/refs.c b/refs.c
index 121774c..f6afd61 100644
--- a/refs.c
+++ b/refs.c
@@ -284,7 +284,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
fd = open(path, O_RDONLY);
if (fd < 0)
return NULL;
- len = read(fd, buffer, sizeof(buffer)-1);
+ len = xread(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
diff --git a/sha1_file.c b/sha1_file.c
index d9622d9..0c9483c 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1869,7 +1869,7 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
if (ret != Z_OK)
break;
}
- size = read(fd, buffer + *bufposn, bufsize - *bufposn);
+ size = xread(fd, buffer + *bufposn, bufsize - *bufposn);
if (size <= 0) {
close(local);
unlink(tmpfile);
diff --git a/ssh-fetch.c b/ssh-fetch.c
index b006c5c..6ec9488 100644
--- a/ssh-fetch.c
+++ b/ssh-fetch.c
@@ -82,7 +82,7 @@ int fetch(unsigned char *sha1)
remote = conn_buf[0];
memmove(conn_buf, conn_buf + 1, --conn_buf_posn);
} else {
- if (read(fd_in, &remote, 1) < 1)
+ if (xread(fd_in, &remote, 1) < 1)
return -1;
}
/* fprintf(stderr, "Got %d\n", remote); */
@@ -99,7 +99,7 @@ static int get_version(void)
char type = 'v';
write(fd_out, &type, 1);
write(fd_out, &local_version, 1);
- if (read(fd_in, &remote_version, 1) < 1) {
+ if (xread(fd_in, &remote_version, 1) < 1) {
return error("Couldn't read version from remote end");
}
return 0;
@@ -111,10 +111,10 @@ int fetch_ref(char *ref, unsigned char *sha1)
char type = 'r';
write(fd_out, &type, 1);
write(fd_out, ref, strlen(ref) + 1);
- read(fd_in, &remote, 1);
+ xread(fd_in, &remote, 1);
if (remote < 0)
return remote;
- read(fd_in, sha1, 20);
+ xread(fd_in, sha1, 20);
return 0;
}
diff --git a/ssh-upload.c b/ssh-upload.c
index 0b52ae1..3f2794c 100644
--- a/ssh-upload.c
+++ b/ssh-upload.c
@@ -23,7 +23,7 @@ static int serve_object(int fd_in, int fd_out) {
signed char remote;
int posn = 0;
do {
- size = read(fd_in, sha1 + posn, 20 - posn);
+ size = xread(fd_in, sha1 + posn, 20 - posn);
if (size < 0) {
perror("git-ssh-upload: read ");
return -1;
@@ -54,7 +54,7 @@ static int serve_object(int fd_in, int fd_out) {
static int serve_version(int fd_in, int fd_out)
{
- if (read(fd_in, &remote_version, 1) < 1)
+ if (xread(fd_in, &remote_version, 1) < 1)
return -1;
write(fd_out, &local_version, 1);
return 0;
@@ -67,7 +67,7 @@ static int serve_ref(int fd_in, int fd_out)
int posn = 0;
signed char remote = 0;
do {
- if (read(fd_in, ref + posn, 1) < 1)
+ if (xread(fd_in, ref + posn, 1) < 1)
return -1;
posn++;
} while (ref[posn - 1]);
@@ -89,7 +89,7 @@ static void service(int fd_in, int fd_out) {
char type;
int retval;
do {
- retval = read(fd_in, &type, 1);
+ retval = xread(fd_in, &type, 1);
if (retval < 1) {
if (retval < 0)
perror("git-ssh-upload: read ");
diff --git a/upload-pack.c b/upload-pack.c
index c568ef0..03a4156 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -242,7 +242,7 @@ static void create_pack_file(void)
*cp++ = buffered;
outsz++;
}
- sz = read(pu_pipe[0], cp,
+ sz = xread(pu_pipe[0], cp,
sizeof(data) - outsz);
if (0 < sz)
;
@@ -267,7 +267,7 @@ static void create_pack_file(void)
/* Status ready; we ship that in the side-band
* or dump to the standard error.
*/
- sz = read(pe_pipe[0], progress,
+ sz = xread(pe_pipe[0], progress,
sizeof(progress));
if (0 < sz)
send_client_data(2, progress, sz);
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR
2007-01-05 10:54 [PATCH] use xread where we are not checking for EAGAIN/EINTR Andy Whitcroft
@ 2007-01-05 11:19 ` Junio C Hamano
2007-01-05 12:20 ` Andy Whitcroft
0 siblings, 1 reply; 10+ messages in thread
From: Junio C Hamano @ 2007-01-05 11:19 UTC (permalink / raw)
To: Andy Whitcroft; +Cc: git
Andy Whitcroft <apw@shadowen.org> writes:
> We have an xread() wrapper to help us with those nasty
> interrupt returns and yet we fail to use it consistently.
> This patch updates those plain read()'s which do not
> have any handling for errors, or which treat those errors
> as user visible fatal errors.
>
> This feels right to me, but perhaps there is some good
> reason that things are done this way ... if so could
> someone elighten me.
Thanks.
I do not think any of the changes you did introduced new bugs,
but I think some of them are still wrong. xread() protects us
from EINTR happening before any byte is read, but it can still
give a short read. Many callers have a loop like this:
do {
size = xread(...);
yet_to_go -= size;
} while (yet_to_go);
but some are not (e.g. add_excludes_from_file_1() in dir.c
expects xread() does not return before reading full buffer).
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR
2007-01-05 11:19 ` Junio C Hamano
@ 2007-01-05 12:20 ` Andy Whitcroft
2007-01-08 15:56 ` Andy Whitcroft
0 siblings, 1 reply; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-05 12:20 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Junio C Hamano wrote:
> Andy Whitcroft <apw@shadowen.org> writes:
>
>> We have an xread() wrapper to help us with those nasty
>> interrupt returns and yet we fail to use it consistently.
>> This patch updates those plain read()'s which do not
>> have any handling for errors, or which treat those errors
>> as user visible fatal errors.
>>
>> This feels right to me, but perhaps there is some good
>> reason that things are done this way ... if so could
>> someone elighten me.
>
> Thanks.
>
> I do not think any of the changes you did introduced new bugs,
> but I think some of them are still wrong. xread() protects us
> from EINTR happening before any byte is read, but it can still
> give a short read. Many callers have a loop like this:
>
> do {
> size = xread(...);
> yet_to_go -= size;
> } while (yet_to_go);
>
> but some are not (e.g. add_excludes_from_file_1() in dir.c
> expects xread() does not return before reading full buffer).
Yes, that is true. I was going to fix that in the next step with the
writes. But yes thats likely to involve them becoming 'read_in_full'
style thing and in fact churn us more.
Ignore this one and I'll look to do it 'right'.
-apw
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR
2007-01-05 12:20 ` Andy Whitcroft
@ 2007-01-08 15:56 ` Andy Whitcroft
2007-01-08 15:57 ` [PATCH 1/4] short i/o: clean up the naming for the write_{in,or}_xxx family Andy Whitcroft
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-08 15:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Andy Whitcroft, git
[-- Attachment #1: Type: text/plain, Size: 1869 bytes --]
Andy Whitcroft wrote:
> Junio C Hamano wrote:
>> Andy Whitcroft <apw@shadowen.org> writes:
>>
>>> We have an xread() wrapper to help us with those nasty
>>> interrupt returns and yet we fail to use it consistently.
>>> This patch updates those plain read()'s which do not
>>> have any handling for errors, or which treat those errors
>>> as user visible fatal errors.
>>>
>>> This feels right to me, but perhaps there is some good
>>> reason that things are done this way ... if so could
>>> someone elighten me.
>> Thanks.
>>
>> I do not think any of the changes you did introduced new bugs,
>> but I think some of them are still wrong. xread() protects us
>> from EINTR happening before any byte is read, but it can still
>> give a short read. Many callers have a loop like this:
>>
>> do {
>> size = xread(...);
>> yet_to_go -= size;
>> } while (yet_to_go);
>>
>> but some are not (e.g. add_excludes_from_file_1() in dir.c
>> expects xread() does not return before reading full buffer).
>
> Yes, that is true. I was going to fix that in the next step with the
> writes. But yes thats likely to involve them becoming 'read_in_full'
> style thing and in fact churn us more.
>
> Ignore this one and I'll look to do it 'right'.
Ok, after much hacking about I think I've got something sensible sorted
out for this. Following this email are four patches which convert the
various read/write/xread/xwrite users over to xread/read_in_full and
xwrite/write_in_full as appropriate. Its pretty invasive as obviously
I/O is pretty common in an SCM.
next with this stack passes the builtin test suite. I additionally used
the attached patch to induce severe short read/write semantics. Before
this patch series git was _very_ unhappy, unable to even create a
repository.
This series is against next.
-apw
[-- Attachment #2: PATCH --]
[-- Type: text/plain, Size: 688 bytes --]
diff --git a/git-compat-util.h b/git-compat-util.h
index 55456da..931cbed 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -210,6 +210,7 @@ static inline void *xmmap(void *start, size_t length,
static inline ssize_t xread(int fd, void *buf, size_t len)
{
ssize_t nr;
+ if (len > 5) len = 5;
while (1) {
nr = read(fd, buf, len);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
@@ -221,6 +222,7 @@ static inline ssize_t xread(int fd, void *buf, size_t len)
static inline ssize_t xwrite(int fd, const void *buf, size_t len)
{
ssize_t nr;
+ if (len > 5) len = 5;
while (1) {
nr = write(fd, buf, len);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 1/4] short i/o: clean up the naming for the write_{in,or}_xxx family
2007-01-08 15:56 ` Andy Whitcroft
@ 2007-01-08 15:57 ` Andy Whitcroft
2007-01-08 15:58 ` [PATCH 2/4] short i/o: fix calls to read to use xread or read_in_full Andy Whitcroft
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-08 15:57 UTC (permalink / raw)
To: git
We recently introduced a write_in_full() which would either write
the specified object or emit an error message and fail. In order
to fix the read side we now want to introduce a read_in_full()
but without an error emit. This patch cleans up the naming
of this family of calls:
1) convert the existing write_or_whine() to write_or_whine_pipe()
to better indicate its pipe specific nature,
2) convert the existing write_in_full() calls to write_or_whine()
to better indicate its nature,
3) introduce a write_in_full() providing a write or fail semantic,
and
4) convert write_or_whine() and write_or_whine_pipe() to use
write_in_full().
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
diff --git a/cache.h b/cache.h
index 36be64e..38a20a8 100644
--- a/cache.h
+++ b/cache.h
@@ -433,9 +433,10 @@ extern char *git_log_output_encoding;
extern int copy_fd(int ifd, int ofd);
extern void read_or_die(int fd, void *buf, size_t count);
-extern int write_in_full(int fd, const void *buf, size_t count, const char *);
+extern int write_in_full(int fd, const void *buf, size_t count);
extern void write_or_die(int fd, const void *buf, size_t count);
extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
+extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
/* pager.c */
extern void setup_pager(void);
diff --git a/send-pack.c b/send-pack.c
index c195d08..6756264 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -65,14 +65,14 @@ static int pack_objects(int fd, struct ref *refs)
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
buf[0] = '^';
buf[41] = '\n';
- if (!write_in_full(pipe_fd[1], buf, 42,
+ if (!write_or_whine(pipe_fd[1], buf, 42,
"send-pack: send refs"))
break;
}
if (!is_null_sha1(refs->new_sha1)) {
memcpy(buf, sha1_to_hex(refs->new_sha1), 40);
buf[40] = '\n';
- if (!write_in_full(pipe_fd[1], buf, 41,
+ if (!write_or_whine(pipe_fd[1], buf, 41,
"send-pack: send refs"))
break;
}
diff --git a/trace.c b/trace.c
index 495e5ed..27fef86 100644
--- a/trace.c
+++ b/trace.c
@@ -101,7 +101,7 @@ void trace_printf(const char *format, ...)
nfvasprintf(&trace_str, format, rest);
va_end(rest);
- write_or_whine(fd, trace_str, strlen(trace_str), err_msg);
+ write_or_whine_pipe(fd, trace_str, strlen(trace_str), err_msg);
free(trace_str);
@@ -139,7 +139,7 @@ void trace_argv_printf(const char **argv, int count, const char *format, ...)
strncpy(trace_str + format_len, argv_str, argv_len);
strcpy(trace_str + trace_len - 1, "\n");
- write_or_whine(fd, trace_str, trace_len, err_msg);
+ write_or_whine_pipe(fd, trace_str, trace_len, err_msg);
free(argv_str);
free(format_str);
diff --git a/write_or_die.c b/write_or_die.c
index 6db1d31..613c0c3 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -35,49 +35,61 @@ void write_or_die(int fd, const void *buf, size_t count)
}
}
-int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
+int write_in_full(int fd, const void *buf, size_t count)
{
const char *p = buf;
- ssize_t written;
+ ssize_t total = 0;
+ ssize_t wcount = 0;
while (count > 0) {
- written = xwrite(fd, p, count);
- if (written == 0) {
- fprintf(stderr, "%s: disk full?\n", msg);
- return 0;
- }
- else if (written < 0) {
- if (errno == EPIPE)
- exit(0);
- fprintf(stderr, "%s: write error (%s)\n",
- msg, strerror(errno));
- return 0;
+ wcount = xwrite(fd, p, count);
+ if (wcount <= 0) {
+ if (total)
+ return total;
+ else
+ return wcount;
}
- count -= written;
- p += written;
+ count -= wcount;
+ p += wcount;
+ total += wcount;
+ }
+
+ return wcount;
+}
+
+int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
+{
+ ssize_t written;
+
+ written = write_in_full(fd, buf, count);
+ if (written == 0) {
+ fprintf(stderr, "%s: disk full?\n", msg);
+ return 0;
+ }
+ else if (written < 0) {
+ if (errno == EPIPE)
+ exit(0);
+ fprintf(stderr, "%s: write error (%s)\n",
+ msg, strerror(errno));
+ return 0;
}
return 1;
}
-int write_in_full(int fd, const void *buf, size_t count, const char *msg)
+int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
{
- const char *p = buf;
ssize_t written;
- while (count > 0) {
- written = xwrite(fd, p, count);
- if (written == 0) {
- fprintf(stderr, "%s: disk full?\n", msg);
- return 0;
- }
- else if (written < 0) {
- fprintf(stderr, "%s: write error (%s)\n",
- msg, strerror(errno));
- return 0;
- }
- count -= written;
- p += written;
+ written = write_in_full(fd, buf, count);
+ if (written == 0) {
+ fprintf(stderr, "%s: disk full?\n", msg);
+ return 0;
+ }
+ else if (written < 0) {
+ fprintf(stderr, "%s: write error (%s)\n",
+ msg, strerror(errno));
+ return 0;
}
return 1;
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/4] short i/o: fix calls to read to use xread or read_in_full
2007-01-08 15:56 ` Andy Whitcroft
2007-01-08 15:57 ` [PATCH 1/4] short i/o: clean up the naming for the write_{in,or}_xxx family Andy Whitcroft
@ 2007-01-08 15:58 ` Andy Whitcroft
2007-01-08 15:58 ` [PATCH 3/4] short i/o: fix calls to write to use xwrite or write_in_full Andy Whitcroft
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-08 15:58 UTC (permalink / raw)
To: git
We have a number of badly checked read() calls. Often we are
expecting read() to read exactly the size we requested or fail, this
fails to handle interrupts or short reads. Add a read_in_full()
providing those semantics. Otherwise we at a minimum need to check
for EINTR and EAGAIN, where this is appropriate use xread().
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
diff --git a/builtin-grep.c b/builtin-grep.c
index 3b1b1cb..2bfbdb7 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -136,7 +136,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
if (i < 0)
goto err_ret;
data = xmalloc(st.st_size + 1);
- if (st.st_size != xread(i, data, st.st_size)) {
+ if (st.st_size != read_in_full(i, data, st.st_size)) {
error("'%s': short read %s", filename, strerror(errno));
close(i);
free(data);
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index 11e62fc..ad802fc 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -74,7 +74,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
char *content = buffer + RECORDSIZE;
ssize_t n;
- n = xread(0, buffer, HEADERSIZE);
+ n = read_in_full(0, buffer, HEADERSIZE);
if (n < HEADERSIZE)
die("git-get-tar-commit-id: read error");
if (header->typeflag[0] != 'g')
diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c
index e4156f8..48ae09e 100644
--- a/builtin-upload-archive.c
+++ b/builtin-upload-archive.c
@@ -91,7 +91,7 @@ static void process_input(int child_fd, int band)
char buf[16384];
ssize_t sz = read(child_fd, buf, sizeof(buf));
if (sz < 0) {
- if (errno != EINTR)
+ if (errno != EAGAIN && errno != EINTR)
error_clnt("read error: %s\n", strerror(errno));
return;
}
diff --git a/cache.h b/cache.h
index 38a20a8..a9583ff 100644
--- a/cache.h
+++ b/cache.h
@@ -432,6 +432,7 @@ extern char *git_commit_encoding;
extern char *git_log_output_encoding;
extern int copy_fd(int ifd, int ofd);
+extern int read_in_full(int fd, void *buf, size_t count);
extern void read_or_die(int fd, void *buf, size_t count);
extern int write_in_full(int fd, const void *buf, size_t count);
extern void write_or_die(int fd, const void *buf, size_t count);
diff --git a/dir.c b/dir.c
index 0338d6c..32b57f0 100644
--- a/dir.c
+++ b/dir.c
@@ -142,7 +142,7 @@ static int add_excludes_from_file_1(const char *fname,
return 0;
}
buf = xmalloc(size+1);
- if (read(fd, buf, size) != size)
+ if (read_in_full(fd, buf, size) != size)
goto err;
close(fd);
diff --git a/http-fetch.c b/http-fetch.c
index 396552d..50a3b00 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -175,7 +175,7 @@ static void start_object_request(struct object_request *obj_req)
prevlocal = open(prevfile, O_RDONLY);
if (prevlocal != -1) {
do {
- prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+ prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
if (prev_read>0) {
if (fwrite_sha1_file(prev_buf,
1,
diff --git a/http-push.c b/http-push.c
index ecefdfd..acb5c27 100644
--- a/http-push.c
+++ b/http-push.c
@@ -288,7 +288,7 @@ static void start_fetch_loose(struct transfer_request *request)
prevlocal = open(prevfile, O_RDONLY);
if (prevlocal != -1) {
do {
- prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+ prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
if (prev_read>0) {
if (fwrite_sha1_file(prev_buf,
1,
diff --git a/imap-send.c b/imap-send.c
index ad91858..8de19e3 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -224,7 +224,7 @@ socket_perror( const char *func, Socket_t *sock, int ret )
static int
socket_read( Socket_t *sock, char *buf, int len )
{
- int n = read( sock->fd, buf, len );
+ int n = xread( sock->fd, buf, len );
if (n <= 0) {
socket_perror( "read", sock, n );
close( sock->fd );
@@ -390,7 +390,7 @@ arc4_init( void )
fprintf( stderr, "Fatal: no random number source available.\n" );
exit( 3 );
}
- if (read( fd, dat, 128 ) != 128) {
+ if (read_in_full( fd, dat, 128 ) != 128) {
fprintf( stderr, "Fatal: cannot read random number source.\n" );
exit( 3 );
}
diff --git a/index-pack.c b/index-pack.c
index 5f6d128..e9a5303 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -638,7 +638,7 @@ static void readjust_pack_header_and_sha1(unsigned char *sha1)
/* Rewrite pack header with updated object number */
if (lseek(output_fd, 0, SEEK_SET) != 0)
die("cannot seek back: %s", strerror(errno));
- if (xread(output_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+ if (read_in_full(output_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
die("cannot read pack header back: %s", strerror(errno));
hdr.hdr_entries = htonl(nr_objects);
if (lseek(output_fd, 0, SEEK_SET) != 0)
diff --git a/local-fetch.c b/local-fetch.c
index 7b6875c..cf99cb7 100644
--- a/local-fetch.c
+++ b/local-fetch.c
@@ -184,7 +184,7 @@ int fetch_ref(char *ref, unsigned char *sha1)
fprintf(stderr, "cannot open %s\n", filename);
return -1;
}
- if (read(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {
+ if (read_in_full(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {
close(ifd);
fprintf(stderr, "cannot read from %s\n", filename);
return -1;
diff --git a/path.c b/path.c
index 066f621..bb5ee7b 100644
--- a/path.c
+++ b/path.c
@@ -113,7 +113,7 @@ int validate_symref(const char *path)
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
- len = read(fd, buffer, sizeof(buffer)-1);
+ len = read_in_full(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
diff --git a/refs.c b/refs.c
index 5205745..2b69e1e 100644
--- a/refs.c
+++ b/refs.c
@@ -284,7 +284,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
fd = open(path, O_RDONLY);
if (fd < 0)
return NULL;
- len = read(fd, buffer, sizeof(buffer)-1);
+ len = read_in_full(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
diff --git a/sha1_file.c b/sha1_file.c
index d9622d9..0c9483c 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1869,7 +1869,7 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
if (ret != Z_OK)
break;
}
- size = read(fd, buffer + *bufposn, bufsize - *bufposn);
+ size = xread(fd, buffer + *bufposn, bufsize - *bufposn);
if (size <= 0) {
close(local);
unlink(tmpfile);
diff --git a/ssh-fetch.c b/ssh-fetch.c
index b006c5c..72965d6 100644
--- a/ssh-fetch.c
+++ b/ssh-fetch.c
@@ -82,7 +82,7 @@ int fetch(unsigned char *sha1)
remote = conn_buf[0];
memmove(conn_buf, conn_buf + 1, --conn_buf_posn);
} else {
- if (read(fd_in, &remote, 1) < 1)
+ if (xread(fd_in, &remote, 1) < 1)
return -1;
}
/* fprintf(stderr, "Got %d\n", remote); */
@@ -99,7 +99,7 @@ static int get_version(void)
char type = 'v';
write(fd_out, &type, 1);
write(fd_out, &local_version, 1);
- if (read(fd_in, &remote_version, 1) < 1) {
+ if (xread(fd_in, &remote_version, 1) < 1) {
return error("Couldn't read version from remote end");
}
return 0;
@@ -111,10 +111,13 @@ int fetch_ref(char *ref, unsigned char *sha1)
char type = 'r';
write(fd_out, &type, 1);
write(fd_out, ref, strlen(ref) + 1);
- read(fd_in, &remote, 1);
+
+ if (read_in_full(fd_in, &remote, 1) != 1)
+ return -1;
if (remote < 0)
return remote;
- read(fd_in, sha1, 20);
+ if (read_in_full(fd_in, sha1, 20) != 20)
+ return -1;
return 0;
}
diff --git a/ssh-upload.c b/ssh-upload.c
index 0b52ae1..2747f96 100644
--- a/ssh-upload.c
+++ b/ssh-upload.c
@@ -21,17 +21,14 @@ static int serve_object(int fd_in, int fd_out) {
ssize_t size;
unsigned char sha1[20];
signed char remote;
- int posn = 0;
- do {
- size = read(fd_in, sha1 + posn, 20 - posn);
- if (size < 0) {
- perror("git-ssh-upload: read ");
- return -1;
- }
- if (!size)
- return -1;
- posn += size;
- } while (posn < 20);
+
+ size = read_in_full(fd_in, sha1, 20);
+ if (size < 0) {
+ perror("git-ssh-upload: read ");
+ return -1;
+ }
+ if (!size)
+ return -1;
if (verbose)
fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1));
@@ -54,7 +51,7 @@ static int serve_object(int fd_in, int fd_out) {
static int serve_version(int fd_in, int fd_out)
{
- if (read(fd_in, &remote_version, 1) < 1)
+ if (xread(fd_in, &remote_version, 1) < 1)
return -1;
write(fd_out, &local_version, 1);
return 0;
@@ -67,7 +64,7 @@ static int serve_ref(int fd_in, int fd_out)
int posn = 0;
signed char remote = 0;
do {
- if (read(fd_in, ref + posn, 1) < 1)
+ if (xread(fd_in, ref + posn, 1) < 1)
return -1;
posn++;
} while (ref[posn - 1]);
@@ -89,7 +86,7 @@ static void service(int fd_in, int fd_out) {
char type;
int retval;
do {
- retval = read(fd_in, &type, 1);
+ retval = xread(fd_in, &type, 1);
if (retval < 1) {
if (retval < 0)
perror("git-ssh-upload: read ");
diff --git a/upload-pack.c b/upload-pack.c
index c568ef0..03a4156 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -242,7 +242,7 @@ static void create_pack_file(void)
*cp++ = buffered;
outsz++;
}
- sz = read(pu_pipe[0], cp,
+ sz = xread(pu_pipe[0], cp,
sizeof(data) - outsz);
if (0 < sz)
;
@@ -267,7 +267,7 @@ static void create_pack_file(void)
/* Status ready; we ship that in the side-band
* or dump to the standard error.
*/
- sz = read(pe_pipe[0], progress,
+ sz = xread(pe_pipe[0], progress,
sizeof(progress));
if (0 < sz)
send_client_data(2, progress, sz);
diff --git a/write_or_die.c b/write_or_die.c
index 613c0c3..e7f8263 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -1,19 +1,36 @@
#include "cache.h"
-void read_or_die(int fd, void *buf, size_t count)
+int read_in_full(int fd, void *buf, size_t count)
{
char *p = buf;
- ssize_t loaded;
+ ssize_t total = 0;
+ ssize_t loaded = 0;
while (count > 0) {
loaded = xread(fd, p, count);
- if (loaded == 0)
- die("unexpected end of file");
- else if (loaded < 0)
- die("read error (%s)", strerror(errno));
+ if (loaded <= 0) {
+ if (total)
+ return total;
+ else
+ return loaded;
+ }
count -= loaded;
p += loaded;
+ total += loaded;
}
+
+ return total;
+}
+
+void read_or_die(int fd, void *buf, size_t count)
+{
+ ssize_t loaded;
+
+ loaded = read_in_full(fd, buf, count);
+ if (loaded == 0)
+ die("unexpected end of file");
+ else if (loaded < 0)
+ die("read error (%s)", strerror(errno));
}
void write_or_die(int fd, const void *buf, size_t count)
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] short i/o: fix calls to write to use xwrite or write_in_full
2007-01-08 15:56 ` Andy Whitcroft
2007-01-08 15:57 ` [PATCH 1/4] short i/o: clean up the naming for the write_{in,or}_xxx family Andy Whitcroft
2007-01-08 15:58 ` [PATCH 2/4] short i/o: fix calls to read to use xread or read_in_full Andy Whitcroft
@ 2007-01-08 15:58 ` Andy Whitcroft
2007-01-08 15:58 ` [PATCH 4/4] short i/o: fix config updates to use write_in_full Andy Whitcroft
` (2 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-08 15:58 UTC (permalink / raw)
To: git
We have a number of badly checked write() calls. Often we are
expecting write() to write exactly the size we requested or fail,
this fails to handle interrupts or short writes. Switch to using
the new write_in_full(). Otherwise we at a minimum need to check
for EINTR and EAGAIN, where this is appropriate use xwrite().
Note, the changes to config handling are much larger and handled
in the next patch in the sequence.
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
diff --git a/builtin-rerere.c b/builtin-rerere.c
index 079c0bd..318d959 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -51,9 +51,11 @@ static int write_rr(struct path_list *rr, int out_fd)
int i;
for (i = 0; i < rr->nr; i++) {
const char *path = rr->items[i].path;
- write(out_fd, rr->items[i].util, 40);
- write(out_fd, "\t", 1);
- write(out_fd, path, strlen(path) + 1);
+ int length = strlen(path) + 1;
+ if (write_in_full(out_fd, rr->items[i].util, 40) != 40 ||
+ write_in_full(out_fd, "\t", 1) != 1 ||
+ write_in_full(out_fd, path, length) != length)
+ die("unable to write rerere record");
}
close(out_fd);
return commit_lock_file(&write_lock);
@@ -244,7 +246,8 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
{
int i;
for (i = 0; i < nbuf; i++)
- write(1, ptr[i].ptr, ptr[i].size);
+ if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)
+ return -1;
return 0;
}
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index ad802fc..8055dda 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -82,7 +82,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
if (memcmp(content, "52 comment=", 11))
return 1;
- n = xwrite(1, content + 11, 41);
+ n = write_in_full(1, content + 11, 41);
if (n < 41)
die("git-get-tar-commit-id: write error");
diff --git a/commit.c b/commit.c
index 2a58175..9ce45ce 100644
--- a/commit.c
+++ b/commit.c
@@ -249,8 +249,10 @@ int write_shallow_commits(int fd, int use_pack_protocol)
if (use_pack_protocol)
packet_write(fd, "shallow %s", hex);
else {
- write(fd, hex, 40);
- write(fd, "\n", 1);
+ if (write_in_full(fd, hex, 40) != 40)
+ break;
+ if (write_in_full(fd, "\n", 1) != 1)
+ break;
}
}
return count;
diff --git a/daemon.c b/daemon.c
index b129b83..f039534 100644
--- a/daemon.c
+++ b/daemon.c
@@ -102,7 +102,7 @@ static void logreport(int priority, const char *err, va_list params)
buf[buflen++] = '\n';
buf[buflen] = '\0';
- write(2, buf, buflen);
+ write_in_full(2, buf, buflen);
}
static void logerror(const char *err, ...)
diff --git a/diff.c b/diff.c
index 1fee15a..f11a633 100644
--- a/diff.c
+++ b/diff.c
@@ -1403,7 +1403,7 @@ static void prep_temp_blob(struct diff_tempfile *temp,
fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX");
if (fd < 0)
die("unable to create temp-file");
- if (write(fd, blob, size) != size)
+ if (write_in_full(fd, blob, size) != size)
die("unable to write temp-file");
close(fd);
temp->name = temp->tmp_path;
diff --git a/entry.c b/entry.c
index 88df713..0ebf0f0 100644
--- a/entry.c
+++ b/entry.c
@@ -89,7 +89,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
return error("git-checkout-index: unable to create file %s (%s)",
path, strerror(errno));
}
- wrote = write(fd, new, size);
+ wrote = write_in_full(fd, new, size);
close(fd);
free(new);
if (wrote != size)
@@ -104,7 +104,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
return error("git-checkout-index: unable to create "
"file %s (%s)", path, strerror(errno));
}
- wrote = write(fd, new, size);
+ wrote = write_in_full(fd, new, size);
close(fd);
free(new);
if (wrote != size)
diff --git a/http-fetch.c b/http-fetch.c
index 50a3b00..fe8cd7b 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -71,7 +71,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
int posn = 0;
struct object_request *obj_req = (struct object_request *)data;
do {
- ssize_t retval = write(obj_req->local,
+ ssize_t retval = xwrite(obj_req->local,
(char *) ptr + posn, size - posn);
if (retval < 0)
return posn;
diff --git a/http-push.c b/http-push.c
index acb5c27..7e73eac 100644
--- a/http-push.c
+++ b/http-push.c
@@ -195,7 +195,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
int posn = 0;
struct transfer_request *request = (struct transfer_request *)data;
do {
- ssize_t retval = write(request->local_fileno,
+ ssize_t retval = xwrite(request->local_fileno,
(char *) ptr + posn, size - posn);
if (retval < 0)
return posn;
diff --git a/imap-send.c b/imap-send.c
index 8de19e3..3eaf025 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -236,7 +236,7 @@ socket_read( Socket_t *sock, char *buf, int len )
static int
socket_write( Socket_t *sock, const char *buf, int len )
{
- int n = write( sock->fd, buf, len );
+ int n = write_in_full( sock->fd, buf, len );
if (n != len) {
socket_perror( "write", sock, n );
close( sock->fd );
diff --git a/index-pack.c b/index-pack.c
index e9a5303..8d10d6b 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -814,7 +814,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
char buf[48];
int len = snprintf(buf, sizeof(buf), "%s\t%s\n",
report, sha1_to_hex(sha1));
- xwrite(1, buf, len);
+ write_in_full(1, buf, len);
/*
* Let's just mimic git-unpack-objects here and write
diff --git a/merge-recursive.c b/merge-recursive.c
index bac16f5..87a27e0 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -517,7 +517,7 @@ static int mkdir_p(const char *path, unsigned long mode)
static void flush_buffer(int fd, const char *buf, unsigned long size)
{
while (size > 0) {
- long ret = xwrite(fd, buf, size);
+ long ret = write_in_full(fd, buf, size);
if (ret < 0) {
/* Ignore epipe */
if (errno == EPIPE)
diff --git a/read-cache.c b/read-cache.c
index 29cf9ab..8ecd826 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -870,7 +870,7 @@ static int ce_write_flush(SHA_CTX *context, int fd)
unsigned int buffered = write_buffer_len;
if (buffered) {
SHA1_Update(context, write_buffer, buffered);
- if (write(fd, write_buffer, buffered) != buffered)
+ if (write_in_full(fd, write_buffer, buffered) != buffered)
return -1;
write_buffer_len = 0;
}
@@ -919,7 +919,7 @@ static int ce_flush(SHA_CTX *context, int fd)
/* Flush first if not enough space for SHA1 signature */
if (left + 20 > WRITE_BUFFER_SIZE) {
- if (write(fd, write_buffer, left) != left)
+ if (write_in_full(fd, write_buffer, left) != left)
return -1;
left = 0;
}
@@ -927,7 +927,7 @@ static int ce_flush(SHA_CTX *context, int fd)
/* Append the SHA1 signature at the end */
SHA1_Final(write_buffer + left, context);
left += 20;
- return (write(fd, write_buffer, left) != left) ? -1 : 0;
+ return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
}
static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
diff --git a/refs.c b/refs.c
index 2b69e1e..4d6fad8 100644
--- a/refs.c
+++ b/refs.c
@@ -332,7 +332,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master)
}
lockpath = mkpath("%s.lock", git_HEAD);
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
- written = write(fd, ref, len);
+ written = write_in_full(fd, ref, len);
close(fd);
if (written != len) {
unlink(lockpath);
@@ -968,7 +968,7 @@ static int log_ref_write(struct ref_lock *lock,
sha1_to_hex(sha1),
committer);
}
- written = len <= maxlen ? write(logfd, logrec, len) : -1;
+ written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
free(logrec);
close(logfd);
if (written != len)
@@ -987,8 +987,8 @@ int write_ref_sha1(struct ref_lock *lock,
unlock_ref(lock);
return 0;
}
- if (write(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
- write(lock->lock_fd, &term, 1) != 1
+ if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
+ write_in_full(lock->lock_fd, &term, 1) != 1
|| close(lock->lock_fd) < 0) {
error("Couldn't write %s", lock->lk->filename);
unlock_ref(lock);
diff --git a/sha1_file.c b/sha1_file.c
index 0c9483c..095a7e1 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1611,20 +1611,13 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
static int write_buffer(int fd, const void *buf, size_t len)
{
- while (len) {
- ssize_t size;
+ ssize_t size;
- size = write(fd, buf, len);
- if (!size)
- return error("file write: disk full");
- if (size < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- return error("file write error (%s)", strerror(errno));
- }
- len -= size;
- buf = (char *) buf + size;
- }
+ size = write_in_full(fd, buf, len);
+ if (!size)
+ return error("file write: disk full");
+ if (size < 0)
+ return error("file write error (%s)", strerror(errno));
return 0;
}
diff --git a/ssh-fetch.c b/ssh-fetch.c
index 72965d6..4c172b6 100644
--- a/ssh-fetch.c
+++ b/ssh-fetch.c
@@ -20,22 +20,6 @@ static int fd_out;
static unsigned char remote_version;
static unsigned char local_version = 1;
-static ssize_t force_write(int fd, void *buffer, size_t length)
-{
- ssize_t ret = 0;
- while (ret < length) {
- ssize_t size = write(fd, (char *) buffer + ret, length - ret);
- if (size < 0) {
- return size;
- }
- if (size == 0) {
- return ret;
- }
- ret += size;
- }
- return ret;
-}
-
static int prefetches;
static struct object_list *in_transit;
@@ -53,8 +37,9 @@ void prefetch(unsigned char *sha1)
node->item = lookup_unknown_object(sha1);
*end_of_transit = node;
end_of_transit = &node->next;
- force_write(fd_out, &type, 1);
- force_write(fd_out, sha1, 20);
+ /* XXX: what if these writes fail? */
+ write_in_full(fd_out, &type, 1);
+ write_in_full(fd_out, sha1, 20);
prefetches++;
}
@@ -97,8 +82,10 @@ int fetch(unsigned char *sha1)
static int get_version(void)
{
char type = 'v';
- write(fd_out, &type, 1);
- write(fd_out, &local_version, 1);
+ if (write_in_full(fd_out, &type, 1) != 1 ||
+ write_in_full(fd_out, &local_version, 1)) {
+ return error("Couldn't request version from remote end");
+ }
if (xread(fd_in, &remote_version, 1) < 1) {
return error("Couldn't read version from remote end");
}
@@ -109,8 +96,10 @@ int fetch_ref(char *ref, unsigned char *sha1)
{
signed char remote;
char type = 'r';
- write(fd_out, &type, 1);
- write(fd_out, ref, strlen(ref) + 1);
+ int length = strlen(ref) + 1;
+ if (write_in_full(fd_out, &type, 1) != 1 ||
+ write_in_full(fd_out, ref, length) != length)
+ return -1;
if (read_in_full(fd_in, &remote, 1) != 1)
return -1;
diff --git a/ssh-upload.c b/ssh-upload.c
index 2747f96..07e61e5 100644
--- a/ssh-upload.c
+++ b/ssh-upload.c
@@ -41,7 +41,8 @@ static int serve_object(int fd_in, int fd_out) {
remote = -1;
}
- write(fd_out, &remote, 1);
+ if (write_in_full(fd_out, &remote, 1) != 1)
+ return 0;
if (remote < 0)
return 0;
@@ -53,7 +54,7 @@ static int serve_version(int fd_in, int fd_out)
{
if (xread(fd_in, &remote_version, 1) < 1)
return -1;
- write(fd_out, &local_version, 1);
+ write_in_full(fd_out, &local_version, 1);
return 0;
}
@@ -74,10 +75,11 @@ static int serve_ref(int fd_in, int fd_out)
if (get_ref_sha1(ref, sha1))
remote = -1;
- write(fd_out, &remote, 1);
+ if (write_in_full(fd_out, &remote, 1) != 1)
+ return 0;
if (remote)
return 0;
- write(fd_out, sha1, 20);
+ write_in_full(fd_out, sha1, 20);
return 0;
}
diff --git a/test-delta.c b/test-delta.c
index 795aa08..16595ef 100644
--- a/test-delta.c
+++ b/test-delta.c
@@ -68,7 +68,7 @@ int main(int argc, char *argv[])
}
fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if (fd < 0 || write(fd, out_buf, out_size) != out_size) {
+ if (fd < 0 || write_in_full(fd, out_buf, out_size) != out_size) {
perror(argv[4]);
return 1;
}
diff --git a/unpack-file.c b/unpack-file.c
index ccddf1d..d24acc2 100644
--- a/unpack-file.c
+++ b/unpack-file.c
@@ -17,7 +17,7 @@ static char *create_temp_file(unsigned char *sha1)
fd = mkstemp(path);
if (fd < 0)
die("unable to create temp-file");
- if (write(fd, buf, size) != size)
+ if (write_in_full(fd, buf, size) != size)
die("unable to write temp-file");
close(fd);
return path;
diff --git a/upload-pack.c b/upload-pack.c
index 03a4156..3a466c6 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -55,6 +55,7 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
/* emergency quit */
fd = 2;
if (fd == 2) {
+ /* XXX: are we happy to lose stuff here? */
xwrite(fd, data, sz);
return sz;
}
diff --git a/write_or_die.c b/write_or_die.c
index e7f8263..a119e1d 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -33,45 +33,40 @@ void read_or_die(int fd, void *buf, size_t count)
die("read error (%s)", strerror(errno));
}
-void write_or_die(int fd, const void *buf, size_t count)
+int write_in_full(int fd, const void *buf, size_t count)
{
const char *p = buf;
- ssize_t written;
+ ssize_t total = 0;
+ ssize_t written = 0;
while (count > 0) {
written = xwrite(fd, p, count);
- if (written == 0)
- die("disk full?");
- else if (written < 0) {
- if (errno == EPIPE)
- exit(0);
- die("write error (%s)", strerror(errno));
+ if (written <= 0) {
+ if (total)
+ return total;
+ else
+ return written;
}
count -= written;
p += written;
+ total += written;
}
+
+ return total;
}
-int write_in_full(int fd, const void *buf, size_t count)
+void write_or_die(int fd, const void *buf, size_t count)
{
- const char *p = buf;
- ssize_t total = 0;
- ssize_t wcount = 0;
+ ssize_t written;
- while (count > 0) {
- wcount = xwrite(fd, p, count);
- if (wcount <= 0) {
- if (total)
- return total;
- else
- return wcount;
- }
- count -= wcount;
- p += wcount;
- total += wcount;
+ written = write_in_full(fd, buf, count);
+ if (written == 0)
+ die("disk full?");
+ else if (written < 0) {
+ if (errno == EPIPE)
+ exit(0);
+ die("write error (%s)", strerror(errno));
}
-
- return wcount;
}
int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] short i/o: fix config updates to use write_in_full
2007-01-08 15:56 ` Andy Whitcroft
` (2 preceding siblings ...)
2007-01-08 15:58 ` [PATCH 3/4] short i/o: fix calls to write to use xwrite or write_in_full Andy Whitcroft
@ 2007-01-08 15:58 ` Andy Whitcroft
2007-01-08 20:13 ` [PATCH] use xread where we are not checking for EAGAIN/EINTR Junio C Hamano
2007-01-11 21:43 ` [PATCH] Avoid errors and warnings when attempting to do I/O on zero bytes Eric Wong
5 siblings, 0 replies; 10+ messages in thread
From: Andy Whitcroft @ 2007-01-08 15:58 UTC (permalink / raw)
To: git
We need to check that the writes we perform during the update of
the users configuration work. Convert to using write_in_full().
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
---
diff --git a/config.c b/config.c
index 5cbd130..2c9d07c 100644
--- a/config.c
+++ b/config.c
@@ -464,7 +464,15 @@ static int store_aux(const char* key, const char* value)
return 0;
}
-static void store_write_section(int fd, const char* key)
+static int write_error()
+{
+ fprintf(stderr, "Failed to write new configuration file\n");
+
+ /* Same error code as "failed to rename". */
+ return 4;
+}
+
+static int store_write_section(int fd, const char* key)
{
const char *dot = strchr(key, '.');
int len1 = store.baselen, len2 = -1;
@@ -478,37 +486,60 @@ static void store_write_section(int fd, const char* key)
}
}
- write(fd, "[", 1);
- write(fd, key, len1);
+ if (write_in_full(fd, "[", 1) != 1 ||
+ write_in_full(fd, key, len1) != len1)
+ return 0;
if (len2 >= 0) {
- write(fd, " \"", 2);
+ if (write_in_full(fd, " \"", 2) != 2)
+ return 0;
while (--len2 >= 0) {
unsigned char c = *++dot;
if (c == '"')
- write(fd, "\\", 1);
- write(fd, &c, 1);
+ if (write_in_full(fd, "\\", 1) != 1)
+ return 0;
+ if (write_in_full(fd, &c, 1) != 1)
+ return 0;
}
- write(fd, "\"", 1);
+ if (write_in_full(fd, "\"", 1) != 1)
+ return 0;
}
- write(fd, "]\n", 2);
+ if (write_in_full(fd, "]\n", 2) != 2)
+ return 0;
+
+ return 1;
}
-static void store_write_pair(int fd, const char* key, const char* value)
+static int store_write_pair(int fd, const char* key, const char* value)
{
int i;
+ int length = strlen(key+store.baselen+1);
- write(fd, "\t", 1);
- write(fd, key+store.baselen+1,
- strlen(key+store.baselen+1));
- write(fd, " = ", 3);
+ if (write_in_full(fd, "\t", 1) != 1 ||
+ write_in_full(fd, key+store.baselen+1, length) != length ||
+ write_in_full(fd, " = ", 3) != 3)
+ return 0;
for (i = 0; value[i]; i++)
switch (value[i]) {
- case '\n': write(fd, "\\n", 2); break;
- case '\t': write(fd, "\\t", 2); break;
- case '"': case '\\': write(fd, "\\", 1);
- default: write(fd, value+i, 1);
- }
- write(fd, "\n", 1);
+ case '\n':
+ if (write_in_full(fd, "\\n", 2) != 2)
+ return 0;
+ break;
+ case '\t':
+ if (write_in_full(fd, "\\t", 2) != 2)
+ return 0;
+ break;
+ case '"':
+ case '\\':
+ if (write_in_full(fd, "\\", 1) != 1)
+ return 0;
+ default:
+ if (write_in_full(fd, value+i, 1) != 1)
+ return 0;
+ break;
+ }
+ if (write_in_full(fd, "\n", 1) != 1)
+ return 0;
+ return 1;
}
static int find_beginning_of_line(const char* contents, int size,
@@ -648,8 +679,11 @@ int git_config_set_multivar(const char* key, const char* value,
}
store.key = (char*)key;
- store_write_section(fd, key);
- store_write_pair(fd, key, value);
+ if (!store_write_section(fd, key) ||
+ !store_write_pair(fd, key, value)) {
+ ret = write_error();
+ goto out_free;
+ }
} else{
struct stat st;
char* contents;
@@ -729,10 +763,10 @@ int git_config_set_multivar(const char* key, const char* value,
/* write the first part of the config */
if (copy_end > copy_begin) {
- write(fd, contents + copy_begin,
+ write_in_full(fd, contents + copy_begin,
copy_end - copy_begin);
if (new_line)
- write(fd, "\n", 1);
+ write_in_full(fd, "\n", 1);
}
copy_begin = store.offset[i];
}
@@ -740,13 +774,19 @@ int git_config_set_multivar(const char* key, const char* value,
/* write the pair (value == NULL means unset) */
if (value != NULL) {
if (store.state == START)
- store_write_section(fd, key);
- store_write_pair(fd, key, value);
+ if (!store_write_section(fd, key)) {
+ ret = write_error();
+ goto out_free;
+ }
+ if (!store_write_pair(fd, key, value)) {
+ ret = write_error();
+ goto out_free;
+ }
}
/* write the rest of the config */
if (copy_begin < st.st_size)
- write(fd, contents + copy_begin,
+ write_in_full(fd, contents + copy_begin,
st.st_size - copy_begin);
munmap(contents, st.st_size);
@@ -800,6 +840,7 @@ int git_config_rename_section(const char *old_name, const char *new_name)
while (fgets(buf, sizeof(buf), config_file)) {
int i;
+ int length;
for (i = 0; buf[i] && isspace(buf[i]); i++)
; /* do nothing */
if (buf[i] == '[') {
@@ -830,15 +871,22 @@ int git_config_rename_section(const char *old_name, const char *new_name)
/* old_name matches */
ret++;
store.baselen = strlen(new_name);
- store_write_section(out_fd, new_name);
+ if (!store_write_section(out_fd, new_name)) {
+ ret = write_error();
+ goto out;
+ }
continue;
}
}
- write(out_fd, buf, strlen(buf));
+ length = strlen(buf);
+ if (write_in_full(out_fd, buf, length) != length) {
+ ret = write_error();
+ goto out;
+ }
}
fclose(config_file);
if (close(out_fd) || commit_lock_file(lock) < 0)
- ret = error("Cannot commit config file!");
+ ret = error("Cannot commit config file!");
out:
free(config_filename);
return ret;
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] use xread where we are not checking for EAGAIN/EINTR
2007-01-08 15:56 ` Andy Whitcroft
` (3 preceding siblings ...)
2007-01-08 15:58 ` [PATCH 4/4] short i/o: fix config updates to use write_in_full Andy Whitcroft
@ 2007-01-08 20:13 ` Junio C Hamano
2007-01-11 21:43 ` [PATCH] Avoid errors and warnings when attempting to do I/O on zero bytes Eric Wong
5 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2007-01-08 20:13 UTC (permalink / raw)
To: Andy Whitcroft; +Cc: git
Thanks. Will queue in 'next' to cook for a few days with the
intent to have it in v1.5.0-rc1.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH] Avoid errors and warnings when attempting to do I/O on zero bytes
2007-01-08 15:56 ` Andy Whitcroft
` (4 preceding siblings ...)
2007-01-08 20:13 ` [PATCH] use xread where we are not checking for EAGAIN/EINTR Junio C Hamano
@ 2007-01-11 21:43 ` Eric Wong
5 siblings, 0 replies; 10+ messages in thread
From: Eric Wong @ 2007-01-11 21:43 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Andy Whitcroft, git
Unfortunately, while {read,write}_in_full do take into account
zero-sized reads/writes; their die and whine variants do not.
I have a repository where there are zero-sized files in
the history that was triggering these things.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
sha1_file.c | 2 ++
write_or_die.c | 8 ++++++++
2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/sha1_file.c b/sha1_file.c
index 53e25f2..18dd89b 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1620,6 +1620,8 @@ static int write_buffer(int fd, const void *buf, size_t len)
{
ssize_t size;
+ if (!len)
+ return 0;
size = write_in_full(fd, buf, len);
if (!size)
return error("file write: disk full");
diff --git a/write_or_die.c b/write_or_die.c
index a119e1d..700ccd1 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -26,6 +26,8 @@ void read_or_die(int fd, void *buf, size_t count)
{
ssize_t loaded;
+ if (!count)
+ return;
loaded = read_in_full(fd, buf, count);
if (loaded == 0)
die("unexpected end of file");
@@ -59,6 +61,8 @@ void write_or_die(int fd, const void *buf, size_t count)
{
ssize_t written;
+ if (!count)
+ return;
written = write_in_full(fd, buf, count);
if (written == 0)
die("disk full?");
@@ -73,6 +77,8 @@ int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
{
ssize_t written;
+ if (!count)
+ return 1;
written = write_in_full(fd, buf, count);
if (written == 0) {
fprintf(stderr, "%s: disk full?\n", msg);
@@ -93,6 +99,8 @@ int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
{
ssize_t written;
+ if (!count)
+ return 1;
written = write_in_full(fd, buf, count);
if (written == 0) {
fprintf(stderr, "%s: disk full?\n", msg);
--
Eric Wong
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2007-01-11 21:43 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-05 10:54 [PATCH] use xread where we are not checking for EAGAIN/EINTR Andy Whitcroft
2007-01-05 11:19 ` Junio C Hamano
2007-01-05 12:20 ` Andy Whitcroft
2007-01-08 15:56 ` Andy Whitcroft
2007-01-08 15:57 ` [PATCH 1/4] short i/o: clean up the naming for the write_{in,or}_xxx family Andy Whitcroft
2007-01-08 15:58 ` [PATCH 2/4] short i/o: fix calls to read to use xread or read_in_full Andy Whitcroft
2007-01-08 15:58 ` [PATCH 3/4] short i/o: fix calls to write to use xwrite or write_in_full Andy Whitcroft
2007-01-08 15:58 ` [PATCH 4/4] short i/o: fix config updates to use write_in_full Andy Whitcroft
2007-01-08 20:13 ` [PATCH] use xread where we are not checking for EAGAIN/EINTR Junio C Hamano
2007-01-11 21:43 ` [PATCH] Avoid errors and warnings when attempting to do I/O on zero bytes Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).