@@ -293,6 +293,11 @@ tests := \
tst-scanf-round \
tst-scanf-to_inpunct \
tst-setvbuf1 \
+ tst-setvbuf2 \
+ tst-setvbuf3 \
+ tst-setvbuf4 \
+ tst-setvbuf5 \
+ tst-setvbuf6 \
tst-sprintf \
tst-sprintf-errno \
tst-sprintf2 \
new file mode 100644
@@ -0,0 +1,71 @@
+/* Test using setvbuf to set unbuffered mode on standard streams.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Check that the standard streams (stdout and stderr) can be set to
+ unbuffered. Note - the POSIX standard indicates that setting the
+ buffering on a stream might not work. It states:
+
+ The setvbuf( ) function may be used after the stream
+ pointed to by stream is associated with an open file
+ but before any other operation (other than an unsuccessful
+ call to setvbuf( )) is performed on the stream.
+
+ Hence if messages have already been written to stdout and/or stderr
+ before this code is executed then we may not be able to change
+ the buffering. The standard does not provide a way to detect if
+ this has happened, so we have to hope for the best. */
+
+/* By default the test harness code will call setvbuf on stdout.
+ Since we want to do this ourselves, we disable the harness'
+ behaviour here. */
+#define TEST_NO_SETVBUF 1
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
+ TEST_VERIFY_EXIT (setvbuf (stderr, NULL, _IONBF, 0) == 0);
+ TEST_VERIFY_EXIT (setvbuf (stdout, NULL, _IONBF, 0) == 0);
+
+ /* The theory was that this test would be run with stdout and stderr
+ redirected into a single file. Then writes to stdout and stderr would
+ be performed with and without newlines and finally the contents of the
+ file would be examined to find out if any buffering has taken place.
+ Unfortunately whilst this works when run by hand, or from a makefile
+ running on an ordinary terminal, it does not work when run by Linaro's
+ CI system.
+
+ There is no way to distinguish Linaro's execution environment from a
+ normal execution environment. (Testing that stdout/stderr are attached
+ to terminals does not work, since they are not - they are attached to an
+ output file: tst-setvbuf.out). All of which means that in the end we
+ cannot test the behaviour of buffering when writing to standard files.
+ (See tst-setvuf4.c and tst-setvbuf5.c for tests that do work when
+ writing to disk based files).
+
+ Hence if we get this far, we consider that the test has passed. */
+
+ return 0;
+}
+
+#include <support/test-driver.c>
new file mode 100644
@@ -0,0 +1,104 @@
+/* Test using setvbuf to set line buffered mode on standard streams.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Check that the standard streams (stdout and stderr) can be set to
+ line buffered. Note - the POSIX standard indicates that setting
+ the buffering on a file might not work. It states:
+
+ The setvbuf( ) function may be used after the stream
+ pointed to by stream is associated with an open file
+ but before any other operation (other than an unsuccessful
+ call to setvbuf( )) is performed on the stream.
+
+ Hence if messages have already been written to stdout and/or stderr,
+ eg by the test harness code, but before this code is executed then
+ the calls to setvbuf might not actually change anything. */
+
+/* By default the test harness code will call setvbuf on stdout.
+ Since we do not want that to happen we use the define below. */
+#define TEST_NO_SETVBUF 1
+
+#include <support/check.h>
+
+#define LOCAL_BUF_SIZE 128
+
+static int
+do_test (void)
+{
+ static char local_buf [LOCAL_BUF_SIZE];
+
+ /* Note - the POSIX standard indicates that setting the buffering on a
+ stream might not give the results expected. It states:
+
+ If BUF is not a null pointer, the array it points to *may*
+ be used instead of a buffer allocated by setvbuf( ) and the
+ argument SIZE specifies the size of the array; otherwise,
+ SIZE *may* determine the size of a buffer allocated by the
+ setvbuf( ) function.
+
+ So whilst we can set the buffering mode, we cannot be certain of the size
+ of the buffer that will be used, or where that buffer will be held. */
+
+ /* Use a library allocated line buffer for stdin. */
+ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IOLBF, LOCAL_BUF_SIZE) == 0);
+
+ /* Note - the POSIX standard also indicates that line buffering might only
+ work on input files:
+
+ Applications should note that many implementations
+ only provide line buffering on input from terminal
+ devices.
+
+ So if the following two calls to setvbuf fail, it is not an error, just
+ an indication that the test cannot be run. */
+
+ /* Use a library allocated line buffer for stderr. */
+ if (setvbuf (stderr, NULL, _IOLBF, LOCAL_BUF_SIZE) != 0)
+ FAIL_UNSUPPORTED ("tst-setvbuf3.c: POSIX standard does not guarantee\
+ being able to set line buffering mode on stderr");
+
+ /* Use a program allocated line buffer for stdout. */
+ if (setvbuf (stdout, local_buf, _IOLBF, sizeof local_buf) != 0)
+ FAIL_UNSUPPORTED ("tst-setvbuf3.c: POSIX standard does not guarantee\
+ being able to set line buffering mode on stdout");
+
+ /* The theory was that this test would be run with stdout and stderr
+ redirected into a single file. Then writes to stdout and stderr would
+ be performed with and without newlines and finally the contents of the
+ file would be examined to find out if any buffering has taken place.
+ Unfortunately whilst this works when run by hand, or from a makefile
+ running on an ordinary terminal, it does not work when run by Linaro's
+ CI system.
+
+ There is no way to distinguish Linaro's execution environment from a
+ normal execution environment. (Testing that stdout/stderr are attached
+ to terminals does not work, since they are not - they are attached to an
+ output file: tst-setvbuf.out). All of which means that in the end we
+ cannot test the behaviour of buffering when writing to standard files.
+ (See tst-setvuf4.c and tst-setvbuf5.c for tests that do work when
+ writing to disk based files).
+
+ Hence if we get this far, we consider that the test has passed. */
+
+ return 0;
+}
+
+#include <support/test-driver.c>
new file mode 100644
@@ -0,0 +1,168 @@
+/* Test using setvbuf to set full buffered mode on a non-terminal file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* Check the behaviour of enabling full buffering on a non-terminal stream.
+
+ Note - the POSIX standard indicates that setting the buffering on a file
+ might not produce the expected results. It states:
+
+ If BUF is not a null pointer, the array it points to *may*
+ be used instead of a buffer allocated by setvbuf() and the
+ argument SIZE specifies the size of the array; otherwise,
+ SIZE *may* determine the size of a buffer allocated by the
+ setvbuf() function.
+
+ So whilst we can set the buffering mode, we cannot be certain of the size
+ of the buffer that will be used, or where that buffer will be held. For
+ now we proceed with the assumption that if the calls to setvbuf succeed
+ then the buffers are the size we expect. But we do not test to see if the
+ buffer we have supplied are the ones actually being used.
+
+ Note - because of the POSIX rules on the interactions of multiple handles
+ on the same stream (see section 2.5.1 "Interaction of File Descriptors
+ and Standard I/O Streams" in the POSIX specification) we cannot just open a
+ file twice, once for reading and once for writing and then check that
+ writes to the file do not happen until the buffer is full. Nor can we
+ open a single stream for both reading and writing and test that way
+ because any time we reposition the file pointer (ie by calling fseek) the
+ buffer is flushed.
+
+ In theory we could use fmemopen() to create a memory backed stream and
+ then check the buffering behaviour that way. But it turns out the glibc's
+ implementation does not support buffering, so that does not work.
+
+ Another alternative is open_memstream() - which does use glibc's default
+ I/O code. But it turns out that the function is not suitable for this test
+ as it specifically does not support having the memory buffer examined after
+ a write has completed but before a flush has been performed.
+
+ So we resort to opening an ordinary file and using mmap to provide us with
+ a memory page that we can examine. */
+
+/* Note - using small buffers here does trigger a bug in glibc's
+ implementation of setvbuf, eg:
+
+ #define BIG_BUF_SIZE 128
+ #define SMALL_BUF_SIZE 12
+
+ The reason for this is explained in a post from Florian:
+
+ https://inbox.sourceware.org/libc-alpha/87jzdqj0qu.fsf@oldenburg.str.redhat.com/
+
+ For now we use larger buffers so that we can test the function with a more
+ reasonable buffer size. */
+
+#define BIG_BUF_SIZE 256
+#define SMALL_BUF_SIZE 128
+
+_Static_assert (SMALL_BUF_SIZE < BIG_BUF_SIZE,
+ "test assumes that its small buffer is shorter than its large buffer");
+_Static_assert (SMALL_BUF_SIZE > 1,
+ "test assumes that its small buffer is more than one byte long");
+
+static char file_buf [SMALL_BUF_SIZE];
+static char small_buf [SMALL_BUF_SIZE];
+static char big_buf [BIG_BUF_SIZE];
+
+static int
+do_test (void)
+{
+ FILE * file;
+ char * mem_page;
+ size_t page_size;
+ int fd;
+ int val;
+
+ TEST_VERIFY_EXIT ((page_size = sysconf (_SC_PAGE_SIZE)) != 0);
+ TEST_VERIFY_EXIT (page_size > SMALL_BUF_SIZE);
+
+ /* Create a temporay file. */
+ TEST_VERIFY_EXIT ((fd = create_temp_file ("tst-setvbuf4", NULL)) != -1);
+
+ /* Create a stream attached to the file. */
+ TEST_VERIFY_EXIT ((file = fdopen (fd, "r+")) != NULL);
+
+ /* Set full buffering on the file, using our (small) file buffer.
+
+ Note - this has to be done now, right after opening the file. The POSIX
+ standard states:
+
+ The setvbuf() function may be used after the stream
+ pointed to by stream is associated with an open file
+ but before any other operation (other than an unsuccessful
+ call to setvbuf( )) is performed on the stream. */
+ TEST_VERIFY_EXIT (setvbuf (file, file_buf, _IOFBF, sizeof file_buf) == 0);
+
+ /* Map the file into memory.
+ FIXME: Using xmmap would simplify this statement, but it would be
+ inconsistent with how we test all of the other library function calls. */
+ TEST_VERIFY_EXIT ((mem_page = mmap (NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) != MAP_FAILED);
+
+ /* The page backing the file has not been initialised yet, so attempts
+ to read from it will produce a SIGBUS error. We fix that by setting
+ the file to the size of the page. */
+ TEST_VERIFY (ftruncate (fd, page_size) == 0);
+
+ /* Create our test data using a value that should not
+ be the same as the contents of the memory page. */
+ val = mem_page[0] + 1;
+ memset (small_buf, val, sizeof small_buf);
+
+ /* Write one byte (which is less than our file buffer size) to the file. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fwrite (small_buf, 1, 1, file) == 1);
+
+ /* Check that the byte has not made it into the file. */
+ TEST_VERIFY (mem_page[0] != val);
+
+ /* Try reading the byte. This would fail, except for the
+ fact that we call fseek() first, which flushes the buffer. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fread (big_buf, 1, 1, file) == 1);
+ TEST_VERIFY (big_buf[0] == small_buf[0]);
+
+ /* Write a whole buffer full. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fwrite (small_buf, 1, sizeof small_buf, file)
+ == sizeof small_buf);
+
+ /* Check that the in-memory buffer now contains these bytes. */
+ TEST_VERIFY (memcmp (small_buf, mem_page, sizeof small_buf) == 0);
+
+ /* Try reading lots of data. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fread (big_buf, 1, sizeof big_buf, file) == sizeof big_buf);
+
+ /* Verify that what we have read the expected bytes. */
+ TEST_VERIFY (memcmp (big_buf, small_buf, sizeof small_buf) == 0);
+
+ fclose (file);
+ return 0;
+}
+
+#include <support/test-driver.c>
new file mode 100644
@@ -0,0 +1,173 @@
+/* Test using setvbuf to set line buffered mode on a non-terminal file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* Check the behaviour of enabling line buffering mode on a non-terminal
+ stream.
+
+ Note - the POSIX standard indicates that setting the buffering on a file
+ might not produce the expected results. It states:
+
+ If BUF is not a null pointer, the array it points to *may*
+ be used instead of a buffer allocated by setvbuf( ) and the
+ argument SIZE specifies the size of the array; otherwise,
+ SIZE *may* determine the size of a buffer allocated by the
+ setvbuf( ) function.
+
+ So whilst we can set the buffering mode, we cannot be certain of the size
+ of the buffer that will be used, or where that buffer will be held. For
+ now we proceed with the assumption that if the calls to setvbuf succeed
+ then the buffers are the size we expect. But we do not test to see if the
+ buffer we have supplied are the ones actually being used.
+
+ Note - the POSIX standard also indicates that line buffering mode might not
+ be supported:
+
+ Applications should note that many implementations only
+ provide line buffering on input from terminal devices.
+
+ So the test first tries to write less than a line of characters. If this
+ shows up in the memory buffer, then we know that line buffering is not
+ supported and the test exits. Otherwise it continues and tests that
+ writing a full line does cause the buffer to be flushed to memory.
+
+ Note - because of the POSIX rules on the interactions of multiple handles
+ on the same stream (see section 2.5.1 "Interaction of File Descriptors
+ and Standard I/O Streams" in the POSIX specification) we cannot just open a
+ file twice, once for reading and once for writing and then check that
+ writes to the file do not happen until the buffer is full. Nor can we
+ open a single stream for both reading and writing and test that way
+ because any time we reposition the file pointer (ie by calling fseek) the
+ buffer is flushed.
+
+ In theory we could use fmemopen() to create a memory backed stream and
+ then check the buffering behaviour that way. But it turns out the glibc's
+ implementation does not support buffering, so that does not work.
+
+ Another alternative is open_memstream() - which does use glibc's default
+ I/O code. But it turns out that the function is not suitable for this test
+ as it specifically does not support having the memory buffer examined after
+ a write has completed but before a flush has been performed.
+
+ So we resort to opening an ordinary file and using mmap to provide us with
+ a memory page that we can examine. */
+
+#define BIG_BUF_SIZE 128
+#define SMALL_BUF_SIZE 12
+
+_Static_assert (SMALL_BUF_SIZE < BIG_BUF_SIZE,
+ "test assumes that its small buffer is shorter than its large buffer");
+_Static_assert (SMALL_BUF_SIZE > 1,
+ "test assumes that its small buffer is more than one byte long");
+
+static char line_buf [SMALL_BUF_SIZE];
+static char in_buf [BIG_BUF_SIZE];
+
+const char string_without_newline[] = "test";
+
+static int
+do_test (void)
+{
+ FILE * file;
+ char * mem_page;
+ size_t page_size;
+ int fd;
+ int len;
+
+ TEST_VERIFY_EXIT ((page_size = sysconf (_SC_PAGE_SIZE)) != 0);
+ TEST_VERIFY_EXIT (page_size > SMALL_BUF_SIZE);
+
+ /* Create a temporay file. */
+ TEST_VERIFY_EXIT ((fd = create_temp_file ("tst-setvbuf5", NULL)) != -1);
+
+ /* Create a stream attached to the file. */
+ TEST_VERIFY_EXIT ((file = fdopen (fd, "r+")) != NULL);
+
+ /* Set line buffering on the file, using our (small) file buffer.
+
+ Note - this has to be done now, right after opening the file. The POSIX
+ standard states:
+
+ The setvbuf() function may be used after the stream
+ pointed to by stream is associated with an open file
+ but before any other operation (other than an unsuccessful
+ call to setvbuf( )) is performed on the stream. */
+ TEST_VERIFY_EXIT (setvbuf (file, line_buf, _IOLBF, sizeof line_buf) == 0);
+
+ /* Map the file into memory.
+ FIXME: Using xmmap would simplify this statement, but it would be
+ inconsistent with how we test all of the other library function calls. */
+ TEST_VERIFY_EXIT ((mem_page = mmap (NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) != MAP_FAILED);
+
+ /* The page backing the file has not been initialised yet, so attempts
+ to read from it will produce a SIGBUS error. We fix that by setting
+ the file to the size of the page. */
+ TEST_VERIFY (ftruncate (fd, page_size) == 0);
+
+ /* Write one byte to the file. */
+ TEST_VERIFY (fwrite (string_without_newline, 1, 1, file) == 1);
+
+ /* Check that the byte has not made it into the file. */
+ if (mem_page[0] == string_without_newline[0])
+ {
+ printf ("info: tst-setvbuf5.c: line buffering is not supported on\
+ non-terminal I/O streams\n");
+ printf ("info: tst-setvbuf5.c: this is allowed by the POSIX standard\n");
+ close (fd);
+ return 0;
+ }
+
+ /* Try reading the byte. This would fail, except for the
+ fact that we call fseek() first, which flushes the buffer. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fread (in_buf, 1, 1, file) == 1);
+ TEST_VERIFY (in_buf[0] == string_without_newline[0]);
+
+ /* Write one and half lines to the file. */
+ len = strlen (string_without_newline);
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fprintf (file, "%s\n%s", string_without_newline,
+ string_without_newline) == len * 2 + 1);
+
+ /* Check that the in-memory buffer now contains the first line. */
+ TEST_VERIFY (strncmp (mem_page, string_without_newline, len) == 0);
+
+ /* And that it does not contain the second line. */
+ TEST_VERIFY (strncmp (mem_page + len + 1, string_without_newline, len) != 0);
+
+ /* Read back what we have written. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fread (in_buf, 1, len * 2 + 1, file) == len * 2 + 1);
+
+ /* Check that we read in the second, not-newline-terminated string. */
+ TEST_VERIFY (strncmp (in_buf + len + 1, string_without_newline, len) == 0);
+
+ fclose (file);
+ return 0;
+}
+
+#include <support/test-driver.c>
new file mode 100644
@@ -0,0 +1,137 @@
+/* Test using setvbuf to set unbuffered mode on a non-terminal file.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* Check the behaviour of setting unbuffered mode on a non-terminal stream.
+
+ Note - because of the POSIX rules on the interactions of multiple handles
+ on the same stream (see section 2.5.1 "Interaction of File Descriptors
+ and Standard I/O Streams" in the POSIX specification) we cannot just open a
+ file twice, once for reading and once for writing and then check that
+ writes to the file happen immediately. Nor can we open a single stream
+ for both reading and writing and test that way because any time we
+ reposition the file pointer (ie by calling fseek) the buffer is flushed.
+
+ In theory we can use fmemopen() to create a memory backed stream and
+ then check the buffering behaviour that way. But it turns out the glibc's
+ implementation does not support buffering, which would not matter for this
+ test except that we want to be sure that buffering is not enabled because
+ of our actions, rather than the library's internal code.
+
+ Another alternative is open_memstream() - which does use glibc's default
+ I/O code. But it turns out that the function is not suitable for this test
+ as it specifically does not support having the memory buffer examined after
+ a write has completed but before a flush has been performed.
+
+ So we resort to opening an ordinary file and using mmap to provide us with
+ a memory page that we can examine. */
+
+#define BIG_BUF_SIZE 128
+#define SMALL_BUF_SIZE 12
+
+_Static_assert (SMALL_BUF_SIZE < BIG_BUF_SIZE,
+ "test assumes that its small buffer is shorter than its large buffer");
+
+static char small_buf [SMALL_BUF_SIZE];
+static char big_buf [BIG_BUF_SIZE];
+
+static int
+do_test (void)
+{
+ FILE * file;
+ char * mem_page;
+ size_t page_size;
+ int fd;
+ int val;
+
+ TEST_VERIFY_EXIT ((page_size = sysconf (_SC_PAGE_SIZE)) != 0);
+ TEST_VERIFY_EXIT (page_size > SMALL_BUF_SIZE);
+
+ /* Create a temporay file. */
+ TEST_VERIFY_EXIT ((fd = create_temp_file ("tst-setvbuf6", NULL)) != -1);
+
+ /* Create a stream attached to the file. */
+ TEST_VERIFY_EXIT ((file = fdopen (fd, "r+")) != NULL);
+
+ /* Disable buffering on the file.
+
+ Note - this has to be done now, right after opening the file. The POSIX
+ standard states:
+
+ The setvbuf() function may be used after the stream
+ pointed to by stream is associated with an open file
+ but before any other operation (other than an unsuccessful
+ call to setvbuf( )) is performed on the stream. */
+ TEST_VERIFY_EXIT (setvbuf (file, NULL, _IONBF, 0) == 0);
+
+ /* Map the file into memory.
+ FIXME: Using xmmap would simplify this statement, but it would be
+ inconsistent with how we test all of the other library function calls. */
+ TEST_VERIFY_EXIT ((mem_page = mmap (NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) != MAP_FAILED);
+
+ /* The page backing the file has not been initialised yet, so attempts
+ to read from it will produce a SIGBUS error. We fix that by setting
+ the file to the size of the page. */
+ TEST_VERIFY (ftruncate (fd, page_size) == 0);
+
+ /* Create our test data using a value that should not
+ be the same as the contents of the memory page. */
+ val = mem_page[0] + 1;
+ memset (small_buf, val, sizeof small_buf);
+
+ /* Write one byte to the file. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fwrite (small_buf, 1, 1, file) == 1);
+
+ /* Check that the byte has made it into the file. */
+ TEST_VERIFY (mem_page[0] == val);
+
+ /* Try reading the byte. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fread (big_buf, 1, 1, file) == 1);
+ TEST_VERIFY (big_buf[0] == small_buf[0]);
+
+ /* Write a whole buffer full. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fwrite (small_buf, 1, sizeof small_buf, file)
+ == sizeof small_buf);
+
+ /* Check that the in-memory buffer now contains these bytes. */
+ TEST_VERIFY (memcmp (small_buf, mem_page, sizeof small_buf) == 0);
+
+ /* Try reading lots of data. */
+ TEST_VERIFY (fseek (file, 0L, SEEK_SET) == 0);
+ TEST_VERIFY (fread (big_buf, 1, sizeof big_buf, file) == sizeof big_buf);
+
+ /* Verify that what we have read the expected bytes. */
+ TEST_VERIFY (memcmp (big_buf, small_buf, sizeof small_buf) == 0);
+
+ fclose (file);
+ return 0;
+}
+
+#include <support/test-driver.c>