summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2020-05-24 13:57:59 +0200
committerBruno Haible <bruno@clisp.org>2020-05-24 13:57:59 +0200
commita7e878621dc2fb8430fccb461b7b669b6bf86190 (patch)
tree23f0b86dfd8eaf63c99fca37f91f691d96b7f774
parentf58691b91ed22372b4a962432aa3ea860fe1cbbb (diff)
downloadgnulib-a7e878621dc2fb8430fccb461b7b669b6bf86190.tar.gz
gnulib-a7e878621dc2fb8430fccb461b7b669b6bf86190.tar.bz2
fopen: Fix the trailing slash workaround.
* lib/fopen.c (rpl_fopen): Parse the mode string. Recognize "r+" as a write access. Pass the right flags to open(). * tests/test-fopen.h (test_fopen): Add a few more tests on directories.
-rw-r--r--ChangeLog7
-rw-r--r--lib/fopen.c42
-rw-r--r--tests/test-fopen.h16
3 files changed, 62 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index c05ef910dc..4dd90f83a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2020-05-24 Bruno Haible <bruno@clisp.org>
+
+ fopen: Fix the trailing slash workaround.
+ * lib/fopen.c (rpl_fopen): Parse the mode string. Recognize "r+" as a
+ write access. Pass the right flags to open().
+ * tests/test-fopen.h (test_fopen): Add a few more tests on directories.
+
2020-05-23 Paul Eggert <eggert@cs.ucla.edu>
assure: new macro ‘affirm’
diff --git a/lib/fopen.c b/lib/fopen.c
index a3128fa8b7..ad6511d2c7 100644
--- a/lib/fopen.c
+++ b/lib/fopen.c
@@ -47,11 +47,47 @@ orig_fopen (const char *filename, const char *mode)
FILE *
rpl_fopen (const char *filename, const char *mode)
{
+ int open_direction;
+ int open_flags_standard;
+
#if defined _WIN32 && ! defined __CYGWIN__
if (strcmp (filename, "/dev/null") == 0)
filename = "NUL";
#endif
+ /* Parse the mode. */
+ open_direction = 0;
+ open_flags_standard = 0;
+ {
+ const char *m;
+
+ for (m = mode; *m != '\0'; m++)
+ {
+ switch (*m)
+ {
+ case 'r':
+ open_direction = O_RDONLY;
+ continue;
+ case 'w':
+ open_direction = O_WRONLY;
+ open_flags_standard |= O_CREAT | O_TRUNC;
+ continue;
+ case 'a':
+ open_direction = O_WRONLY;
+ open_flags_standard |= O_CREAT | O_APPEND;
+ continue;
+ case 'b':
+ continue;
+ case '+':
+ open_direction = O_RDWR;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
#if FOPEN_TRAILING_SLASH_BUG
/* Fail if the mode requires write access and the filename ends in a slash,
as POSIX says such a filename must name a directory
@@ -74,13 +110,13 @@ rpl_fopen (const char *filename, const char *mode)
struct stat statbuf;
FILE *fp;
- if (mode[0] == 'w' || mode[0] == 'a')
+ if (open_direction != O_RDONLY)
{
errno = EISDIR;
return NULL;
}
- fd = open (filename, O_RDONLY);
+ fd = open (filename, open_direction | open_flags_standard);
if (fd < 0)
return NULL;
@@ -101,7 +137,7 @@ rpl_fopen (const char *filename, const char *mode)
return fp;
}
}
-# endif
+#endif
return orig_fopen (filename, mode);
}
diff --git a/tests/test-fopen.h b/tests/test-fopen.h
index fb036af6b7..875cdaf981 100644
--- a/tests/test-fopen.h
+++ b/tests/test-fopen.h
@@ -47,6 +47,10 @@ test_fopen (void)
ASSERT (fopen (BASE "file/", "r") == NULL);
ASSERT (errno == ENOTDIR || errno == EISDIR || errno == EINVAL);
+ errno = 0;
+ ASSERT (fopen (BASE "file/", "r+") == NULL);
+ ASSERT (errno == ENOTDIR || errno == EISDIR || errno == EINVAL);
+
/* Cannot create a directory. */
errno = 0;
ASSERT (fopen ("nonexist.ent/", "w") == NULL);
@@ -58,6 +62,18 @@ test_fopen (void)
ASSERT (fopen (".", "w") == NULL);
ASSERT (errno == EISDIR || errno == EINVAL || errno == EACCES);
+ errno = 0;
+ ASSERT (fopen ("./", "w") == NULL);
+ ASSERT (errno == EISDIR || errno == EINVAL || errno == EACCES);
+
+ errno = 0;
+ ASSERT (fopen (".", "r+") == NULL);
+ ASSERT (errno == EISDIR || errno == EINVAL || errno == EACCES);
+
+ errno = 0;
+ ASSERT (fopen ("./", "r+") == NULL);
+ ASSERT (errno == EISDIR || errno == EINVAL || errno == EACCES);
+
/* /dev/null must exist, and be writable. */
f = fopen ("/dev/null", "r");
ASSERT (f);

Return to:

Send suggestions and report system problems to the System administrator.