Skip to content

Commit 8e14b27

Browse files
committed
Make fread() more consistent with glibc
1 parent 1d532ba commit 8e14b27

File tree

3 files changed

+57
-24
lines changed

3 files changed

+57
-24
lines changed

libc/stdio/fread_unlocked.c

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,27 @@
2828
#include "libc/sysv/consts/o.h"
2929
#include "libc/sysv/errfuns.h"
3030

31-
static ssize_t readvall(int fd, struct iovec *iov, int iovlen) {
31+
static ssize_t readvall(FILE *f, struct iovec *iov, int iovlen, size_t need) {
3232
ssize_t rc;
3333
size_t got, toto;
34-
toto = 0;
35-
do {
36-
if ((rc = readv(fd, iov, iovlen)) == -1) {
37-
if (toto) {
38-
if (errno == EINTR)
39-
continue;
34+
for (toto = 0;;) {
35+
36+
// perform i/o
37+
if ((rc = readv(f->fd, iov, iovlen)) == -1) {
38+
f->state = errno;
39+
if (toto)
4040
return toto;
41-
}
4241
return -1;
4342
}
4443
got = rc;
4544
toto += got;
45+
if (!got) {
46+
f->state = EOF;
47+
return toto;
48+
}
49+
50+
// roll forward iov
51+
// skip over empty elements
4652
for (;;) {
4753
if (!iov->iov_len) {
4854
--iovlen;
@@ -56,9 +62,14 @@ static ssize_t readvall(int fd, struct iovec *iov, int iovlen) {
5662
iov->iov_len -= got;
5763
break;
5864
}
65+
if (!iovlen)
66+
return toto;
5967
}
60-
} while (got && iovlen);
61-
return toto;
68+
69+
// don't trigger eof condition if we're rolling greed to fill buffer
70+
if (toto >= need)
71+
return toto;
72+
}
6273
}
6374

6475
/**
@@ -134,27 +145,16 @@ size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
134145
iov[1].iov_base = NULL;
135146
iov[1].iov_len = 0;
136147
}
137-
if (f->bufmode == _IONBF) {
138-
rc = readv(f->fd, iov, 2);
139-
} else {
140-
rc = readvall(f->fd, iov, 2);
141-
}
142-
if (rc == -1) {
143-
f->state = errno;
148+
rc = readvall(f, iov, 2, need);
149+
if (rc == -1)
144150
return 0;
145-
}
146151
got = rc;
147152

148153
// handle partial fulfillment
149154
if (got < need) {
150155
got += m;
151-
if (got % stride) {
152-
f->state = eio();
153-
return 0;
154-
}
155156
f->beg = 0;
156157
f->end = 0;
157-
f->state = EOF;
158158
return got / stride;
159159
}
160160

test/libc/stdio/fputc_test.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ void SetUpOnce(void) {
3333
TEST(fputc, test) {
3434
ASSERT_NE(NULL, (f = fopen("hog", "w+")));
3535
EXPECT_EQ('h', fputc('h', f));
36+
EXPECT_FALSE(feof(f));
3637
EXPECT_EQ(0xFF, fputc(-1, f));
38+
EXPECT_FALSE(feof(f));
3739
EXPECT_NE(-1, fseek(f, 0, SEEK_SET));
40+
EXPECT_FALSE(feof(f));
3841
EXPECT_EQ('h', fgetc(f));
42+
EXPECT_FALSE(feof(f));
3943
EXPECT_EQ(0, fread(NULL, 0, 0, f));
4044
EXPECT_FALSE(feof(f));
4145
EXPECT_EQ(0xFF, fgetc(f));

test/libc/stdio/fread_test.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/calls.h"
20+
#include "libc/errno.h"
2021
#include "libc/stdio/stdio.h"
2122
#include "libc/testlib/testlib.h"
2223

@@ -45,7 +46,7 @@ TEST(fread, eofIsSticky) {
4546
}
4647

4748
TEST(fread, seekWithBuffer) {
48-
FILE *f;
49+
FILE* f;
4950
char b[8] = "hellosup";
5051
char c[8] = {0};
5152
char d[8] = {0};
@@ -60,3 +61,31 @@ TEST(fread, seekWithBuffer) {
6061
ASSERT_STREQ("ellos", d);
6162
ASSERT_EQ(0, fclose(f));
6263
}
64+
65+
TEST(fread, zero) {
66+
FILE* f;
67+
char buf[8] = {0};
68+
ASSERT_NE(NULL, (f = fopen("foo", "w")));
69+
ASSERT_EQ(2, fwrite("hi", 1, 2, f));
70+
ASSERT_EQ(0, fclose(f));
71+
ASSERT_NE(NULL, (f = fopen("foo", "r")));
72+
ASSERT_EQ(0, fread(buf, 0, 0, f));
73+
ASSERT_EQ(0, ferror(stdin));
74+
ASSERT_EQ(0, feof(stdin));
75+
ASSERT_STREQ("", buf);
76+
ASSERT_EQ(0, fclose(f));
77+
}
78+
79+
TEST(fread, partial) {
80+
FILE* f;
81+
char buf[8] = {0};
82+
ASSERT_NE(NULL, (f = fopen("foo", "w")));
83+
ASSERT_EQ(2, fwrite("hi", 1, 2, f));
84+
ASSERT_EQ(0, fclose(f));
85+
ASSERT_NE(NULL, (f = fopen("foo", "r")));
86+
ASSERT_EQ(0, fread(buf, 8, 1, f));
87+
ASSERT_EQ(0, ferror(stdin));
88+
ASSERT_EQ(0, feof(stdin));
89+
ASSERT_EQ(0, fclose(f));
90+
ASSERT_STREQ("hi", buf);
91+
}

0 commit comments

Comments
 (0)