summaryrefslogtreecommitdiff
path: root/lib/fopen.c
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 /lib/fopen.c
parentf58691b91ed22372b4a962432aa3ea860fe1cbbb (diff)
downloadgnulib-a7e878621dc2fb8430fccb461b7b669b6bf86190.tar.gz
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.
Diffstat (limited to 'lib/fopen.c')
-rw-r--r--lib/fopen.c42
1 files changed, 39 insertions, 3 deletions
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);
}