gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

fopen.c
Go to the documentation of this file.
1 /* Open a stream to a file.
2  Copyright (C) 2007-2021 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 <https://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 _GL_ALREADY_INCLUDING_STDIO_H
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 _GL_ALREADY_INCLUDING_STDIO_H
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 <stdbool.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 
48 FILE *
49 rpl_fopen (const char *filename, const char *mode)
50 {
51  int open_direction;
52  int open_flags;
53 #if GNULIB_FOPEN_GNU
54  bool open_flags_gnu;
55 # define BUF_SIZE 80
56  char fdopen_mode_buf[BUF_SIZE + 1];
57 #endif
58 
59 #if defined _WIN32 && ! defined __CYGWIN__
60  if (strcmp (filename, "/dev/null") == 0)
61  filename = "NUL";
62 #endif
63 
64  /* Parse the mode. */
65  open_direction = 0;
66  open_flags = 0;
67 #if GNULIB_FOPEN_GNU
68  open_flags_gnu = false;
69 #endif
70  {
71  const char *p = mode;
72 #if GNULIB_FOPEN_GNU
73  char *q = fdopen_mode_buf;
74 #endif
75 
76  for (; *p != '\0'; p++)
77  {
78  switch (*p)
79  {
80  case 'r':
81  open_direction = O_RDONLY;
82 #if GNULIB_FOPEN_GNU
83  if (q < fdopen_mode_buf + BUF_SIZE)
84  *q++ = *p;
85 #endif
86  continue;
87  case 'w':
88  open_direction = O_WRONLY;
89  open_flags |= O_CREAT | O_TRUNC;
90 #if GNULIB_FOPEN_GNU
91  if (q < fdopen_mode_buf + BUF_SIZE)
92  *q++ = *p;
93 #endif
94  continue;
95  case 'a':
96  open_direction = O_WRONLY;
97  open_flags |= O_CREAT | O_APPEND;
98 #if GNULIB_FOPEN_GNU
99  if (q < fdopen_mode_buf + BUF_SIZE)
100  *q++ = *p;
101 #endif
102  continue;
103  case 'b':
104  /* While it is non-standard, O_BINARY is guaranteed by
105  gnulib <fcntl.h>. We can also assume that orig_fopen
106  supports the 'b' flag. */
107  open_flags |= O_BINARY;
108 #if GNULIB_FOPEN_GNU
109  if (q < fdopen_mode_buf + BUF_SIZE)
110  *q++ = *p;
111 #endif
112  continue;
113  case '+':
114  open_direction = O_RDWR;
115 #if GNULIB_FOPEN_GNU
116  if (q < fdopen_mode_buf + BUF_SIZE)
117  *q++ = *p;
118 #endif
119  continue;
120 #if GNULIB_FOPEN_GNU
121  case 'x':
122  open_flags |= O_EXCL;
123  open_flags_gnu = true;
124  continue;
125  case 'e':
126  open_flags |= O_CLOEXEC;
127  open_flags_gnu = true;
128  continue;
129 #endif
130  default:
131  break;
132  }
133 #if GNULIB_FOPEN_GNU
134  /* The rest of the mode string can be a platform-dependent extension.
135  Copy it unmodified. */
136  {
137  size_t len = strlen (p);
138  if (len > fdopen_mode_buf + BUF_SIZE - q)
139  len = fdopen_mode_buf + BUF_SIZE - q;
140  memcpy (q, p, len);
141  q += len;
142  }
143 #endif
144  break;
145  }
146 #if GNULIB_FOPEN_GNU
147  *q = '\0';
148 #endif
149  }
150 
151 #if FOPEN_TRAILING_SLASH_BUG
152  /* Fail if the mode requires write access and the filename ends in a slash,
153  as POSIX says such a filename must name a directory
154  <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
155  "A pathname that contains at least one non-<slash> character and that
156  ends with one or more trailing <slash> characters shall not be resolved
157  successfully unless the last pathname component before the trailing
158  <slash> characters names an existing directory"
159  If the named file already exists as a directory, then if a mode that
160  requires write access is specified, fopen() must fail because POSIX
161  <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html>
162  says that it fails with errno = EISDIR in this case.
163  If the named file does not exist or does not name a directory, then
164  fopen() must fail since the file does not contain a '.' directory. */
165  {
166  size_t len = strlen (filename);
167  if (len > 0 && filename[len - 1] == '/')
168  {
169  int fd;
170  struct stat statbuf;
171  FILE *fp;
172 
173  if (open_direction != O_RDONLY)
174  {
175  errno = EISDIR;
176  return NULL;
177  }
178 
179  fd = open (filename, open_direction | open_flags,
181  if (fd < 0)
182  return NULL;
183 
184  if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
185  {
186  close (fd);
187  errno = ENOTDIR;
188  return NULL;
189  }
190 
191 # if GNULIB_FOPEN_GNU
192  fp = fdopen (fd, fdopen_mode_buf);
193 # else
194  fp = fdopen (fd, mode);
195 # endif
196  if (fp == NULL)
197  {
198  int saved_errno = errno;
199  close (fd);
200  errno = saved_errno;
201  }
202  return fp;
203  }
204  }
205 #endif
206 
207 #if GNULIB_FOPEN_GNU
208  if (open_flags_gnu)
209  {
210  int fd;
211  FILE *fp;
212 
213  fd = open (filename, open_direction | open_flags,
215  if (fd < 0)
216  return NULL;
217 
218  fp = fdopen (fd, fdopen_mode_buf);
219  if (fp == NULL)
220  {
221  int saved_errno = errno;
222  close (fd);
223  errno = saved_errno;
224  }
225  return fp;
226  }
227 #endif
228 
229  return orig_fopen (filename, mode);
230 }
FILE * rpl_fopen(const char *filename, const char *mode)
Definition: fopen.c:49
static FILE * orig_fopen(const char *filename, const char *mode)
Definition: fopen.c:30
#define O_BINARY
Definition: fcntl.in.h:398
#define O_CLOEXEC
Definition: fcntl.in.h:291
int open(const char *filename, int flags,...)
Definition: open.c:59
#define NULL
Definition: stddef.in.h:72
#define S_IROTH
Definition: sys_stat.in.h:339
#define S_IRGRP
Definition: sys_stat.in.h:336
#define S_IWOTH
Definition: sys_stat.in.h:352
#define S_ISDIR(m)
Definition: sys_stat.in.h:195
#define S_IRUSR
Definition: sys_stat.in.h:333
#define S_IWUSR
Definition: sys_stat.in.h:346
#define S_IWGRP
Definition: sys_stat.in.h:349
const char * p
Definition: mbrtowc-impl.h:42