forked from rpms/glibc
740 lines
22 KiB
Diff
740 lines
22 KiB
Diff
|
commit ed4bb289cf739f537deb735eaa01be531df084b9
|
||
|
Author: Joseph Myers <josmyers@redhat.com>
|
||
|
Date: Wed Sep 4 16:32:21 2024 +0000
|
||
|
|
||
|
Add more thorough tests of freopen
|
||
|
|
||
|
freopen is rather minimally tested in libio/tst-freopen and
|
||
|
libio/test-freopen. Add some more thorough tests, covering different
|
||
|
cases for change of mode in particular. The tests are run for both
|
||
|
freopen and freopen64 (given that those functions have two separate
|
||
|
copies of much of the code, so any bug fix directly in the freopen
|
||
|
code would probably need applying in both places).
|
||
|
|
||
|
Note that there are two parts of the tests disabled because of bugs
|
||
|
discovered through running the tests, with bug numbers given in
|
||
|
comments. I expect to address those separately. The tests also don't
|
||
|
cover changes to cancellation ("c" in mode); I think that will better
|
||
|
be handled through a separate test. Also to handle separately:
|
||
|
testing on stdin / stdout / stderr; documenting lack of support for
|
||
|
streams opened with popen / fmemopen / open_memstream / fopencookie;
|
||
|
maybe also a chroot test without /proc; maybe also more thorough tests
|
||
|
for large file handling on 32-bit systems (freopen64).
|
||
|
|
||
|
Tested for x86_64.
|
||
|
|
||
|
Conflicts:
|
||
|
stdio-common/Makefile
|
||
|
(tst-fread already backported)
|
||
|
|
||
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||
|
index ea8598bbe3a6dfdd..5eddc4bfbf4e7fb9 100644
|
||
|
--- a/stdio-common/Makefile
|
||
|
+++ b/stdio-common/Makefile
|
||
|
@@ -175,6 +175,10 @@ tests := \
|
||
|
tst-fphex \
|
||
|
tst-fphex-wide \
|
||
|
tst-fread \
|
||
|
+ tst-freopen2 \
|
||
|
+ tst-freopen3 \
|
||
|
+ tst-freopen64-2 \
|
||
|
+ tst-freopen64-3 \
|
||
|
tst-fseek \
|
||
|
tst-fwrite \
|
||
|
tst-getline \
|
||
|
@@ -246,6 +250,8 @@ tests-special += \
|
||
|
ifeq (yes,$(build-shared))
|
||
|
ifneq ($(PERL),no)
|
||
|
tests-special += \
|
||
|
+ $(objpfx)tst-freopen2-mem.out \
|
||
|
+ $(objpfx)tst-freopen64-2-mem.out \
|
||
|
$(objpfx)tst-getline-enomem-mem.out \
|
||
|
$(objpfx)tst-getline-mem.out \
|
||
|
$(objpfx)tst-printf-bz18872-mem.out \
|
||
|
@@ -256,6 +262,10 @@ tests-special += \
|
||
|
# tests-special
|
||
|
|
||
|
generated += \
|
||
|
+ tst-freopen2-mem.out \
|
||
|
+ tst-freopen2.mtrace \
|
||
|
+ tst-freopen64-2-mem.out \
|
||
|
+ tst-freopen64-2.mtrace \
|
||
|
tst-getline-enomem-mem.out \
|
||
|
tst-getline-enomem.mtrace \
|
||
|
tst-getline-mem.out \
|
||
|
@@ -328,6 +338,12 @@ tst-getline-ENV = \
|
||
|
tst-getline-enomem-ENV = \
|
||
|
MALLOC_TRACE=$(objpfx)tst-getline-enomem.mtrace \
|
||
|
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
|
||
|
+tst-freopen2-ENV = \
|
||
|
+ MALLOC_TRACE=$(objpfx)tst-freopen2.mtrace \
|
||
|
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
|
||
|
+tst-freopen64-2-ENV = \
|
||
|
+ MALLOC_TRACE=$(objpfx)tst-freopen64-2.mtrace \
|
||
|
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
|
||
|
|
||
|
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
|
||
|
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
|
||
|
diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..22b21afebf709563
|
||
|
--- /dev/null
|
||
|
+++ b/stdio-common/tst-freopen2-main.c
|
||
|
@@ -0,0 +1,526 @@
|
||
|
+/* Test freopen.
|
||
|
+ 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 <errno.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <mcheck.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <wchar.h>
|
||
|
+
|
||
|
+#include <support/check.h>
|
||
|
+#include <support/descriptors.h>
|
||
|
+#include <support/file_contents.h>
|
||
|
+#include <support/support.h>
|
||
|
+#include <support/temp_file.h>
|
||
|
+#include <support/test-driver.h>
|
||
|
+#include <support/xstdio.h>
|
||
|
+
|
||
|
+#define START_TEST(DESC) \
|
||
|
+ do \
|
||
|
+ { \
|
||
|
+ fds = support_descriptors_list (); \
|
||
|
+ verbose_printf (DESC); \
|
||
|
+ } \
|
||
|
+ while (0)
|
||
|
+
|
||
|
+#define END_TEST \
|
||
|
+ do \
|
||
|
+ { \
|
||
|
+ support_descriptors_check (fds); \
|
||
|
+ support_descriptors_free (fds); \
|
||
|
+ } \
|
||
|
+ while (0)
|
||
|
+
|
||
|
+int
|
||
|
+do_test (void)
|
||
|
+{
|
||
|
+ mtrace ();
|
||
|
+ struct support_descriptors *fds;
|
||
|
+ char *temp_dir = support_create_temp_directory ("tst-freopen2");
|
||
|
+ char *file1 = xasprintf ("%s/file1", temp_dir);
|
||
|
+ support_write_file_string (file1, "file1");
|
||
|
+ add_temp_file (file1);
|
||
|
+ char *file2 = xasprintf ("%s/file2", temp_dir);
|
||
|
+ support_write_file_string (file2, "file2");
|
||
|
+ add_temp_file (file2);
|
||
|
+ char *file3 = xasprintf ("%s/file3", temp_dir);
|
||
|
+ char *file4 = xasprintf ("%s/file4", temp_dir);
|
||
|
+ char *file1a = xasprintf ("%s/file1a", temp_dir);
|
||
|
+ FILE *fp;
|
||
|
+ int ret;
|
||
|
+ wint_t wc;
|
||
|
+
|
||
|
+ /* Test each pair of old and new modes from r w a. */
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> r\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "file2");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> w\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("File2new", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file1, "file1");
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "File2new");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> a\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "a", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("3", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "File2new3");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing w -> r\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "File2new3");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing w -> w\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("next", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file1, "");
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "next");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing w -> a\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ fp = FREOPEN (file2, "a", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("4", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "next4");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing a -> r\n");
|
||
|
+ fp = xfopen (file1, "a");
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "next4");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing a -> w\n");
|
||
|
+ fp = xfopen (file1, "a");
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("another", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing a -> a\n");
|
||
|
+ fp = xfopen (file1, "a");
|
||
|
+ fp = FREOPEN (file2, "a", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("5", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another5");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test for file originally opened with fopen64. */
|
||
|
+ START_TEST ("Testing fopen64 a -> a\n");
|
||
|
+ fp = fopen64 (file1, "a");
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ fp = FREOPEN (file2, "a", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("64", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another564");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test calling freopen more than once on the same FILE *. */
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> w -> r\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("freopen-twice", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice");
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "freopen-twice");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> w -> r (exactly one freopen64)\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = OTHER_FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("freopen-twice64", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64");
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "freopen-twice64");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test changing to/from b (binary, no-op). */
|
||
|
+
|
||
|
+ START_TEST ("Testing rb -> r\n");
|
||
|
+ fp = xfopen (file1, "rb");
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> rb\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "rb", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test changing to/from + (read-and-write). */
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> w+\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "w+", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("latest", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ ret = fseek (fp, 0, SEEK_SET);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "latest");
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "latest");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing w -> a+\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ fp = FREOPEN (file2, "a+", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("suffix", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ ret = fseek (fp, 0, SEEK_SET);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "latestsuffix");
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "latestsuffix");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing a -> r+\n");
|
||
|
+ fp = xfopen (file1, "a");
|
||
|
+ fp = FREOPEN (file2, "r+", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "latestsuffix");
|
||
|
+ ret = fseek (fp, 0, SEEK_SET);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ ret = fputs ("new", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "newestsuffix");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r+ -> w\n");
|
||
|
+ fp = xfopen (file1, "r+");
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("plusto", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ ret = fseek (fp, 0, SEEK_SET);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ errno = 0;
|
||
|
+ TEST_COMPARE (fgetc (fp), EOF);
|
||
|
+ TEST_COMPARE (errno, EBADF);
|
||
|
+ clearerr (fp);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plusto");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing w+ -> a\n");
|
||
|
+ fp = xfopen (file1, "w+");
|
||
|
+ fp = FREOPEN (file2, "a", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("more", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ ret = fseek (fp, 0, SEEK_SET);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ errno = 0;
|
||
|
+ TEST_COMPARE (fgetc (fp), EOF);
|
||
|
+ TEST_COMPARE (errno, EBADF);
|
||
|
+ clearerr (fp);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plustomore");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing a+ -> r\n");
|
||
|
+ fp = xfopen (file1, "a+");
|
||
|
+ fp = FREOPEN (file2, "rr", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
|
||
|
+ ret = fputs ("2", fp);
|
||
|
+ TEST_COMPARE (ret, EOF);
|
||
|
+ clearerr (fp);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plustomore");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test changing to/from e (FD_CLOEXEC). */
|
||
|
+
|
||
|
+ START_TEST ("Testing re -> r\n");
|
||
|
+ fp = xfopen (file1, "re");
|
||
|
+ ret = fcntl (fileno (fp), F_GETFD);
|
||
|
+ TEST_VERIFY (ret != -1);
|
||
|
+ TEST_COMPARE (ret & FD_CLOEXEC, FD_CLOEXEC);
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fcntl (fileno (fp), F_GETFD);
|
||
|
+ TEST_VERIFY (ret != -1);
|
||
|
+#if 0 /* Fails to clear FD_CLOEXEC (bug 32134). */
|
||
|
+ TEST_COMPARE (ret & FD_CLOEXEC, 0);
|
||
|
+#endif
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> re\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ ret = fcntl (fileno (fp), F_GETFD);
|
||
|
+ TEST_VERIFY (ret != -1);
|
||
|
+ TEST_COMPARE (ret & FD_CLOEXEC, 0);
|
||
|
+ fp = FREOPEN (file2, "re", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fcntl (fileno (fp), F_GETFD);
|
||
|
+ TEST_VERIFY (ret != -1);
|
||
|
+ TEST_COMPARE (ret & FD_CLOEXEC, FD_CLOEXEC);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test changing to/from m (mmap) (a no-op as far as testing
|
||
|
+ semantics is concerned). */
|
||
|
+
|
||
|
+ START_TEST ("Testing rm -> r\n");
|
||
|
+ fp = xfopen (file1, "rm");
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing r -> rm\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fp = FREOPEN (file2, "rm", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "plustomore");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test changing to/from x (O_EXCL). */
|
||
|
+
|
||
|
+ START_TEST ("Testing wx -> w\n");
|
||
|
+ fp = xfopen (file3, "wx");
|
||
|
+ add_temp_file (file3);
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ ret = fputs ("wxtow", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "wxtow");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("Testing w -> wx (file does not exist)\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ fp = FREOPEN (file4, "wx", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ add_temp_file (file4);
|
||
|
+ ret = fputs ("wtowx", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ xfclose (fp);
|
||
|
+ TEST_OPEN_AND_COMPARE_FILE_STRING (file4, "wtowx");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test with ,ccs=CHARSET. */
|
||
|
+
|
||
|
+ START_TEST ("testing w,ccs=utf-8 -> r\n");
|
||
|
+ fp = xfopen (file1, "w,ccs=utf-8");
|
||
|
+ ret = fputws (L"\xc0\xc1", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "wxtow");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("testing w,ccs=iso-8859-1 -> r,ccs=utf-8\n");
|
||
|
+ fp = xfopen (file2, "w,ccs=iso-8859-1");
|
||
|
+ ret = fputws (L"\xc0\xc1", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+#if 0 /* Doesn't work (bug 23675). */
|
||
|
+ fp = FREOPEN (file1, "r,ccs=utf-8", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+#else /* Works instead. */
|
||
|
+ xfclose (fp);
|
||
|
+ fp = xfopen (file1, "r,ccs=utf-8");
|
||
|
+#endif
|
||
|
+ wc = fgetwc (fp);
|
||
|
+ TEST_COMPARE (wc, (wint_t) 0xc0);
|
||
|
+ wc = fgetwc (fp);
|
||
|
+ TEST_COMPARE (wc, (wint_t) 0xc1);
|
||
|
+ wc = fgetwc (fp);
|
||
|
+ TEST_COMPARE (wc, WEOF);
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("testing r,ccs=utf-8 -> r\n");
|
||
|
+ fp = xfopen (file1, "r,ccs=utf-8");
|
||
|
+ fp = FREOPEN (file1, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "\u00c0\u00c1");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test that errors closing the old file are ignored. */
|
||
|
+
|
||
|
+ START_TEST ("testing errors closing old file ignored\n");
|
||
|
+ fp = xfopen ("/dev/full", "w");
|
||
|
+ fputc ('x', fp);
|
||
|
+ fp = FREOPEN (file1, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "\u00c0\u00c1");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test that error / EOF state from the old file are cleared. */
|
||
|
+
|
||
|
+ START_TEST ("testing error state from old file cleared\n");
|
||
|
+ fp = xfopen ("/dev/full", "w");
|
||
|
+ fputc ('x', fp);
|
||
|
+ fflush (fp);
|
||
|
+ TEST_VERIFY (ferror (fp));
|
||
|
+ TEST_VERIFY (!feof (fp));
|
||
|
+ fp = FREOPEN (file2, "w", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_VERIFY (!ferror (fp));
|
||
|
+ TEST_VERIFY (!feof (fp));
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ START_TEST ("testing EOF state from old file cleared\n");
|
||
|
+ fp = xfopen ("/dev/null", "r");
|
||
|
+ fgetc (fp);
|
||
|
+ TEST_VERIFY (!ferror (fp));
|
||
|
+ TEST_VERIFY (feof (fp));
|
||
|
+ fp = FREOPEN (file2, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_VERIFY (!ferror (fp));
|
||
|
+ TEST_VERIFY (!feof (fp));
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test freopen with NULL, same mode (should flush content and reset
|
||
|
+ file offset). */
|
||
|
+
|
||
|
+ START_TEST ("testing freopen with NULL, same mode\n");
|
||
|
+ fp = xfopen (file1, "r+");
|
||
|
+ ret = fputs ("same mode", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ fp = FREOPEN (NULL, "r+", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "same mode");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test freopen with NULL, different mode. */
|
||
|
+
|
||
|
+ START_TEST ("testing freopen with NULL, different mode\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ ret = fputs ("different mode", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ fp = FREOPEN (NULL, "r", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "different mode");
|
||
|
+ xfclose (fp);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test freopen with NULL, renamed file. This verifies that
|
||
|
+ reopening succeeds (and resets the file position indicator to
|
||
|
+ start of file) even when the original path could no longer be
|
||
|
+ opened. */
|
||
|
+
|
||
|
+ START_TEST ("testing freopen with NULL, renamed file\n");
|
||
|
+ fp = xfopen (file1, "r+");
|
||
|
+ ret = fputs ("file has been renamed", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ ret = rename (file1, file1a);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ fp = FREOPEN (NULL, "r+", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "file has been renamed");
|
||
|
+ xfclose (fp);
|
||
|
+ ret = rename (file1a, file1);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test freopen with NULL, deleted file. This verifies that
|
||
|
+ reopening succeeds (and resets the file position indicator to
|
||
|
+ start of file) even when the original path could no longer be
|
||
|
+ opened. */
|
||
|
+
|
||
|
+ START_TEST ("testing freopen with NULL, deleted file\n");
|
||
|
+ fp = xfopen (file1, "r+");
|
||
|
+ ret = fputs ("file has now been deleted", fp);
|
||
|
+ TEST_VERIFY (ret >= 0);
|
||
|
+ ret = remove (file1);
|
||
|
+ TEST_COMPARE (ret, 0);
|
||
|
+ fp = FREOPEN (NULL, "r+", fp);
|
||
|
+ TEST_VERIFY_EXIT (fp != NULL);
|
||
|
+ TEST_COMPARE_FILE_STRING (fp, "file has now been deleted");
|
||
|
+ xfclose (fp);
|
||
|
+ /* Recreate the file so it is present when expected for temporary
|
||
|
+ file deletion. */
|
||
|
+ support_write_file_string (file1, "file1");
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ free (temp_dir);
|
||
|
+ free (file1);
|
||
|
+ free (file2);
|
||
|
+ free (file3);
|
||
|
+ free (file4);
|
||
|
+ free (file1a);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#include <support/test-driver.c>
|
||
|
diff --git a/stdio-common/tst-freopen2.c b/stdio-common/tst-freopen2.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..11ec7a9783b7caa3
|
||
|
--- /dev/null
|
||
|
+++ b/stdio-common/tst-freopen2.c
|
||
|
@@ -0,0 +1,3 @@
|
||
|
+#define FREOPEN freopen
|
||
|
+#define OTHER_FREOPEN freopen64
|
||
|
+#include <tst-freopen2-main.c>
|
||
|
diff --git a/stdio-common/tst-freopen3-main.c b/stdio-common/tst-freopen3-main.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..5107e1f98e189e4b
|
||
|
--- /dev/null
|
||
|
+++ b/stdio-common/tst-freopen3-main.c
|
||
|
@@ -0,0 +1,90 @@
|
||
|
+/* Test freopen failure.
|
||
|
+ 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 <errno.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+
|
||
|
+#include <support/check.h>
|
||
|
+#include <support/descriptors.h>
|
||
|
+#include <support/file_contents.h>
|
||
|
+#include <support/support.h>
|
||
|
+#include <support/temp_file.h>
|
||
|
+#include <support/test-driver.h>
|
||
|
+#include <support/xstdio.h>
|
||
|
+
|
||
|
+#define START_TEST(DESC) \
|
||
|
+ do \
|
||
|
+ { \
|
||
|
+ fds = support_descriptors_list (); \
|
||
|
+ verbose_printf (DESC); \
|
||
|
+ } \
|
||
|
+ while (0)
|
||
|
+
|
||
|
+#define END_TEST \
|
||
|
+ do \
|
||
|
+ { \
|
||
|
+ support_descriptors_check (fds); \
|
||
|
+ support_descriptors_free (fds); \
|
||
|
+ } \
|
||
|
+ while (0)
|
||
|
+
|
||
|
+int
|
||
|
+do_test (void)
|
||
|
+{
|
||
|
+ struct support_descriptors *fds;
|
||
|
+ char *temp_dir = support_create_temp_directory ("tst-freopen3");
|
||
|
+ char *file1 = xasprintf ("%s/file1", temp_dir);
|
||
|
+ support_write_file_string (file1, "file1");
|
||
|
+ add_temp_file (file1);
|
||
|
+ char *file2 = xasprintf ("%s/file2", temp_dir);
|
||
|
+ support_write_file_string (file2, "file2");
|
||
|
+ add_temp_file (file2);
|
||
|
+ char *file_nodir = xasprintf ("%s/nodir/file", temp_dir);
|
||
|
+ FILE *fp;
|
||
|
+ int ret;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ START_TEST ("Testing w -> wx (file exists)\n");
|
||
|
+ fp = xfopen (file1, "w");
|
||
|
+ fp = FREOPEN (file2, "wx", fp);
|
||
|
+ TEST_VERIFY (fp == NULL);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ /* Test old file is closed even when opening the new file fails. */
|
||
|
+
|
||
|
+ START_TEST ("testing r -> r (opening new file fails)\n");
|
||
|
+ fp = xfopen (file1, "r");
|
||
|
+ fd = fileno (fp);
|
||
|
+ fp = FREOPEN (file_nodir, "r", fp);
|
||
|
+ TEST_VERIFY (fp == NULL);
|
||
|
+ errno = 0;
|
||
|
+ ret = fcntl (fd, F_GETFL);
|
||
|
+ TEST_COMPARE (ret, -1);
|
||
|
+ TEST_COMPARE (errno, EBADF);
|
||
|
+ END_TEST;
|
||
|
+
|
||
|
+ free (temp_dir);
|
||
|
+ free (file1);
|
||
|
+ free (file2);
|
||
|
+ free (file_nodir);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#include <support/test-driver.c>
|
||
|
diff --git a/stdio-common/tst-freopen3.c b/stdio-common/tst-freopen3.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..5041b6b2332c8af1
|
||
|
--- /dev/null
|
||
|
+++ b/stdio-common/tst-freopen3.c
|
||
|
@@ -0,0 +1,2 @@
|
||
|
+#define FREOPEN freopen
|
||
|
+#include <tst-freopen3-main.c>
|
||
|
diff --git a/stdio-common/tst-freopen64-2.c b/stdio-common/tst-freopen64-2.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..88fdc64d8c6548f5
|
||
|
--- /dev/null
|
||
|
+++ b/stdio-common/tst-freopen64-2.c
|
||
|
@@ -0,0 +1,3 @@
|
||
|
+#define FREOPEN freopen64
|
||
|
+#define OTHER_FREOPEN freopen
|
||
|
+#include <tst-freopen2-main.c>
|
||
|
diff --git a/stdio-common/tst-freopen64-3.c b/stdio-common/tst-freopen64-3.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..b91b6d2c033a1a79
|
||
|
--- /dev/null
|
||
|
+++ b/stdio-common/tst-freopen64-3.c
|
||
|
@@ -0,0 +1,2 @@
|
||
|
+#define FREOPEN freopen64
|
||
|
+#include <tst-freopen3-main.c>
|