]> git.cworth.org Git - tar/blob - gnu/open.c
Imported Upstream version 1.24
[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-2010 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 #include <config.h>
22
23 /* Get the original definition of open.  It might be defined as a macro.  */
24 #define __need_system_fcntl_h
25 #include <fcntl.h>
26 #undef __need_system_fcntl_h
27 #include <sys/types.h>
28
29 static inline int
30 orig_open (const char *filename, int flags, mode_t mode)
31 {
32   return open (filename, flags, mode);
33 }
34
35 /* Specification.  */
36 #include <fcntl.h>
37
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44
45 #ifndef REPLACE_OPEN_DIRECTORY
46 # define REPLACE_OPEN_DIRECTORY 0
47 #endif
48
49 int
50 open (const char *filename, int flags, ...)
51 {
52   mode_t mode;
53   int fd;
54
55   mode = 0;
56   if (flags & O_CREAT)
57     {
58       va_list arg;
59       va_start (arg, flags);
60
61       /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
62          creates crashing code when 'mode_t' is smaller than 'int'.  */
63       mode = va_arg (arg, PROMOTED_MODE_T);
64
65       va_end (arg);
66     }
67
68 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
69   if (strcmp (filename, "/dev/null") == 0)
70     filename = "NUL";
71 #endif
72
73 #if OPEN_TRAILING_SLASH_BUG
74   /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR
75      is specified, then fail.
76      Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
77      says that
78        "A pathname that contains at least one non-slash character and that
79         ends with one or more trailing slashes shall be resolved as if a
80         single dot character ( '.' ) were appended to the pathname."
81      and
82        "The special filename dot shall refer to the directory specified by
83         its predecessor."
84      If the named file already exists as a directory, then
85        - if O_CREAT is specified, open() must fail because of the semantics
86          of O_CREAT,
87        - if O_WRONLY or O_RDWR is specified, open() must fail because POSIX
88          <http://www.opengroup.org/susv3/functions/open.html> says that it
89          fails with errno = EISDIR in this case.
90      If the named file does not exist or does not name a directory, then
91        - if O_CREAT is specified, open() must fail since open() cannot create
92          directories,
93        - if O_WRONLY or O_RDWR is specified, open() must fail because the
94          file does not contain a '.' directory.  */
95   if (flags & (O_CREAT | O_WRONLY | O_RDWR))
96     {
97       size_t len = strlen (filename);
98       if (len > 0 && filename[len - 1] == '/')
99         {
100           errno = EISDIR;
101           return -1;
102         }
103     }
104 #endif
105
106   fd = orig_open (filename, flags, mode);
107
108 #if REPLACE_FCHDIR
109   /* Implementing fchdir and fdopendir requires the ability to open a
110      directory file descriptor.  If open doesn't support that (as on
111      mingw), we use a dummy file that behaves the same as directories
112      on Linux (ie. always reports EOF on attempts to read()), and
113      override fstat() in fchdir.c to hide the fact that we have a
114      dummy.  */
115   if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
116       && ((flags & O_ACCMODE) == O_RDONLY
117           || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH)))
118     {
119       struct stat statbuf;
120       if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
121         {
122           /* Maximum recursion depth of 1.  */
123           fd = open ("/dev/null", flags, mode);
124           if (0 <= fd)
125             fd = _gl_register_fd (fd, filename);
126         }
127       else
128         errno = EACCES;
129     }
130 #endif
131
132 #if OPEN_TRAILING_SLASH_BUG
133   /* If the filename ends in a slash and fd does not refer to a directory,
134      then fail.
135      Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
136      says that
137        "A pathname that contains at least one non-slash character and that
138         ends with one or more trailing slashes shall be resolved as if a
139         single dot character ( '.' ) were appended to the pathname."
140      and
141        "The special filename dot shall refer to the directory specified by
142         its predecessor."
143      If the named file without the slash is not a directory, open() must fail
144      with ENOTDIR.  */
145   if (fd >= 0)
146     {
147       /* We know len is positive, since open did not fail with ENOENT.  */
148       size_t len = strlen (filename);
149       if (filename[len - 1] == '/')
150         {
151           struct stat statbuf;
152
153           if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
154             {
155               close (fd);
156               errno = ENOTDIR;
157               return -1;
158             }
159         }
160     }
161 #endif
162
163 #if REPLACE_FCHDIR
164   if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
165     fd = _gl_register_fd (fd, filename);
166 #endif
167
168   return fd;
169 }