1/* Open a stream to a file. 2 Copyright (C) 2007-2012 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ 18 19/* If the user's config.h happens to include <stdio.h>, let it include only 20 the system's <stdio.h> here, so that orig_fopen doesn't recurse to 21 rpl_fopen. */ 22#define __need_FILE 23#include <config.h> 24 25/* Get the original definition of fopen. It might be defined as a macro. */ 26#include <stdio.h> 27#undef __need_FILE 28 29static FILE * 30orig_fopen (const char *filename, const char *mode) 31{ 32 return fopen (filename, mode); 33} 34 35/* Specification. */ 36/* Write "stdio.h" here, not <stdio.h>, otherwise OSF/1 5.1 DTK cc eliminates 37 this include because of the preliminary #include <stdio.h> above. */ 38#include "stdio.h" 39 40#include <errno.h> 41#include <fcntl.h> 42#include <string.h> 43#include <unistd.h> 44#include <sys/types.h> 45#include <sys/stat.h> 46 47FILE * 48rpl_fopen (const char *filename, const char *mode) 49{ 50#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 51 if (strcmp (filename, "/dev/null") == 0) 52 filename = "NUL"; 53#endif 54 55#if FOPEN_TRAILING_SLASH_BUG 56 /* If the filename ends in a slash and a mode that requires write access is 57 specified, then fail. 58 Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html> 59 says that 60 "A pathname that contains at least one non-slash character and that 61 ends with one or more trailing slashes shall be resolved as if a 62 single dot character ( '.' ) were appended to the pathname." 63 and 64 "The special filename dot shall refer to the directory specified by 65 its predecessor." 66 If the named file already exists as a directory, then if a mode that 67 requires write access is specified, fopen() must fail because POSIX 68 <http://www.opengroup.org/susv3/functions/fopen.html> says that it 69 fails with errno = EISDIR in this case. 70 If the named file does not exist or does not name a directory, then 71 fopen() must fail since the file does not contain a '.' directory. */ 72 { 73 size_t len = strlen (filename); 74 if (len > 0 && filename[len - 1] == '/') 75 { 76 int fd; 77 struct stat statbuf; 78 FILE *fp; 79 80 if (mode[0] == 'w' || mode[0] == 'a') 81 { 82 errno = EISDIR; 83 return NULL; 84 } 85 86 fd = open (filename, O_RDONLY); 87 if (fd < 0) 88 return NULL; 89 90 if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) 91 { 92 close (fd); 93 errno = ENOTDIR; 94 return NULL; 95 } 96 97 fp = fdopen (fd, mode); 98 if (fp == NULL) 99 { 100 int saved_errno = errno; 101 close (fd); 102 errno = saved_errno; 103 } 104 return fp; 105 } 106 } 107# endif 108 109 return orig_fopen (filename, mode); 110} 111