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 (at) 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 29 static FILE * 30 orig_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 47 FILE * 48 rpl_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