06e60205794bb94829985f27263786a0880eaa4a
[debian/tar] / gnu / open.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Open a descriptor to a file.
4    Copyright (C) 2007-2014 Free Software Foundation, Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
20
21 /* If the user's config.h happens to include <fcntl.h>, let it include only
22    the system's <fcntl.h> here, so that orig_open doesn't recurse to
23    rpl_open.  */
24 #define __need_system_fcntl_h
25 #include <config.h>
26
27 /* Get the original definition of open.  It might be defined as a macro.  */
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #undef __need_system_fcntl_h
31
32 static int
33 orig_open (const char *filename, int flags, mode_t mode)
34 {
35   return open (filename, flags, mode);
36 }
37
38 /* Specification.  */
39 /* Write "fcntl.h" here, not <fcntl.h>, otherwise OSF/1 5.1 DTK cc eliminates
40    this include because of the preliminary #include <fcntl.h> above.  */
41 #include "fcntl.h"
42
43 #include <errno.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49
50 #ifndef REPLACE_OPEN_DIRECTORY
51 # define REPLACE_OPEN_DIRECTORY 0
52 #endif
53
54 int
55 open (const char *filename, int flags, ...)
56 {
57   mode_t mode;
58   int fd;
59
60   mode = 0;
61   if (flags & O_CREAT)
62     {
63       va_list arg;
64       va_start (arg, flags);
65
66       /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
67          creates crashing code when 'mode_t' is smaller than 'int'.  */
68       mode = va_arg (arg, PROMOTED_MODE_T);
69
70       va_end (arg);
71     }
72
73 #if GNULIB_defined_O_NONBLOCK
74   /* The only known platform that lacks O_NONBLOCK is mingw, but it
75      also lacks named pipes and Unix sockets, which are the only two
76      file types that require non-blocking handling in open().
77      Therefore, it is safe to ignore O_NONBLOCK here.  It is handy
78      that mingw also lacks openat(), so that is also covered here.  */
79   flags &= ~O_NONBLOCK;
80 #endif
81
82 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
83   if (strcmp (filename, "/dev/null") == 0)
84     filename = "NUL";
85 #endif
86
87 #if OPEN_TRAILING_SLASH_BUG
88   /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR
89      is specified, then fail.
90      Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
91      says that
92        "A pathname that contains at least one non-slash character and that
93         ends with one or more trailing slashes shall be resolved as if a
94         single dot character ( '.' ) were appended to the pathname."
95      and
96        "The special filename dot shall refer to the directory specified by
97         its predecessor."
98      If the named file already exists as a directory, then
99        - if O_CREAT is specified, open() must fail because of the semantics
100          of O_CREAT,
101        - if O_WRONLY or O_RDWR is specified, open() must fail because POSIX
102          <http://www.opengroup.org/susv3/functions/open.html> says that it
103          fails with errno = EISDIR in this case.
104      If the named file does not exist or does not name a directory, then
105        - if O_CREAT is specified, open() must fail since open() cannot create
106          directories,
107        - if O_WRONLY or O_RDWR is specified, open() must fail because the
108          file does not contain a '.' directory.  */
109   if (flags & (O_CREAT | O_WRONLY | O_RDWR))
110     {
111       size_t len = strlen (filename);
112       if (len > 0 && filename[len - 1] == '/')
113         {
114           errno = EISDIR;
115           return -1;
116         }
117     }
118 #endif
119
120   fd = orig_open (filename, flags, mode);
121
122 #if REPLACE_FCHDIR
123   /* Implementing fchdir and fdopendir requires the ability to open a
124      directory file descriptor.  If open doesn't support that (as on
125      mingw), we use a dummy file that behaves the same as directories
126      on Linux (ie. always reports EOF on attempts to read()), and
127      override fstat() in fchdir.c to hide the fact that we have a
128      dummy.  */
129   if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
130       && ((flags & O_ACCMODE) == O_RDONLY
131           || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH)))
132     {
133       struct stat statbuf;
134       if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
135         {
136           /* Maximum recursion depth of 1.  */
137           fd = open ("/dev/null", flags, mode);
138           if (0 <= fd)
139             fd = _gl_register_fd (fd, filename);
140         }
141       else
142         errno = EACCES;
143     }
144 #endif
145
146 #if OPEN_TRAILING_SLASH_BUG
147   /* If the filename ends in a slash and fd does not refer to a directory,
148      then fail.
149      Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
150      says that
151        "A pathname that contains at least one non-slash character and that
152         ends with one or more trailing slashes shall be resolved as if a
153         single dot character ( '.' ) were appended to the pathname."
154      and
155        "The special filename dot shall refer to the directory specified by
156         its predecessor."
157      If the named file without the slash is not a directory, open() must fail
158      with ENOTDIR.  */
159   if (fd >= 0)
160     {
161       /* We know len is positive, since open did not fail with ENOENT.  */
162       size_t len = strlen (filename);
163       if (filename[len - 1] == '/')
164         {
165           struct stat statbuf;
166
167           if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
168             {
169               close (fd);
170               errno = ENOTDIR;
171               return -1;
172             }
173         }
174     }
175 #endif
176
177 #if REPLACE_FCHDIR
178   if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
179     fd = _gl_register_fd (fd, filename);
180 #endif
181
182   return fd;
183 }