summaryrefslogtreecommitdiff
path: root/lib/fopen.c
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2008-09-24 13:50:02 +0200
committerBruno Haible <bruno@clisp.org>2008-09-24 13:50:02 +0200
commit955345ebebdae2b894b5a3d8e21036335cb13e5d (patch)
tree88c5bbed1030d85eb4fc73020132122e1324f803 /lib/fopen.c
parent91a109c0426e8b8cd8b317e29c8a91bd99757f0a (diff)
downloadgnulib-955345ebebdae2b894b5a3d8e21036335cb13e5d.tar.gz
Ensure that a filename ending in a slash cannot be used to access a non-directory.
Diffstat (limited to 'lib/fopen.c')
-rw-r--r--lib/fopen.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/lib/fopen.c b/lib/fopen.c
index 5143001831..f64122b9f1 100644
--- a/lib/fopen.c
+++ b/lib/fopen.c
@@ -22,12 +22,19 @@
#include <stdio.h>
#include <errno.h>
+#include <fcntl.h>
#include <string.h>
+#include <unistd.h>
FILE *
rpl_fopen (const char *filename, const char *mode)
#undef fopen
{
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ if (strcmp (filename, "/dev/null") == 0)
+ filename = "NUL";
+#endif
+
#if FOPEN_TRAILING_SLASH_BUG
/* If the filename ends in a slash and a mode that requires write access is
specified, then fail.
@@ -45,21 +52,41 @@ rpl_fopen (const char *filename, const char *mode)
fails with errno = EISDIR in this case.
If the named file does not exist or does not name a directory, then
fopen() must fail since the file does not contain a '.' directory. */
- if (mode[0] == 'w' || mode[0] == 'a')
- {
- size_t len = strlen (filename);
- if (len > 0 && filename[len - 1] == '/')
- {
- errno = EISDIR;
+ {
+ size_t len = strlen (filename);
+ if (len > 0 && filename[len - 1] == '/')
+ {
+ int fd;
+ struct stat statbuf;
+ FILE *fp;
+
+ if (mode[0] == 'w' || mode[0] == 'a')
+ {
+ errno = EISDIR;
+ return NULL;
+ }
+
+ fd = open (filename, O_RDONLY);
+ if (fd < 0)
return NULL;
- }
- }
-#endif
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
- if (strcmp (filename, "/dev/null") == 0)
- filename = "NUL";
-#endif
+ if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
+ {
+ errno = ENOTDIR;
+ return NULL;
+ }
+
+ fp = fdopen (fd, mode);
+ if (fp == NULL)
+ {
+ int saved_errno = errno;
+ close (fd);
+ errno = saved_errno;
+ }
+ return fp;
+ }
+ }
+# endif
return fopen (filename, mode);
}