]>
Commit | Line | Data |
---|---|---|
688903eb | 1 | /* Copyright (C) 1993-2018 Free Software Foundation, Inc. |
41bdb6e2 | 2 | This file is part of the GNU C Library. |
96aa2d94 | 3 | |
41bdb6e2 AJ |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public | |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
96aa2d94 | 8 | |
41bdb6e2 AJ |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
40a55d20 | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
41bdb6e2 | 12 | Lesser General Public License for more details. |
96aa2d94 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. | |
96aa2d94 | 17 | |
41bdb6e2 AJ |
18 | As a special exception, if you link the code in this file with |
19 | files compiled with a GNU compiler to produce an executable, | |
20 | that does not cause the resulting executable to be covered by | |
21 | the GNU Lesser General Public License. This exception does not | |
22 | however invalidate any other reasons why the executable file | |
23 | might be covered by the GNU Lesser General Public License. | |
24 | This exception applies to code released by its copyright holders | |
25 | in files containing the exception. */ | |
96aa2d94 | 26 | |
c8a89e7d | 27 | #include <stdlib.h> |
96aa2d94 RM |
28 | #include "libioP.h" |
29 | #include <fcntl.h> | |
30 | ||
5f0704b6 | 31 | #include <shlib-compat.h> |
96aa2d94 RM |
32 | |
33 | _IO_FILE * | |
9d46370c | 34 | _IO_new_fdopen (int fd, const char *mode) |
96aa2d94 RM |
35 | { |
36 | int read_write; | |
edf5b2d7 UD |
37 | struct locked_FILE |
38 | { | |
bd355af0 | 39 | struct _IO_FILE_plus fp; |
499e7464 | 40 | #ifdef _IO_MTSAFE_IO |
edf5b2d7 | 41 | _IO_lock_t lock; |
499e7464 | 42 | #endif |
d64b6ad0 | 43 | struct _IO_wide_data wd; |
edf5b2d7 | 44 | } *new_f; |
dd0ee2e1 UD |
45 | int i; |
46 | int use_mmap = 0; | |
96aa2d94 | 47 | |
ae42bbc5 SP |
48 | /* Decide whether we modify the offset of the file we attach to and seek to |
49 | the end of file. We only do this if the mode is 'a' and if the file | |
50 | descriptor did not have O_APPEND in its flags already. */ | |
51 | bool do_seek = false; | |
52 | ||
dd0ee2e1 | 53 | switch (*mode) |
96aa2d94 RM |
54 | { |
55 | case 'r': | |
56 | read_write = _IO_NO_WRITES; | |
57 | break; | |
58 | case 'w': | |
59 | read_write = _IO_NO_READS; | |
60 | break; | |
61 | case 'a': | |
96aa2d94 RM |
62 | read_write = _IO_NO_READS|_IO_IS_APPENDING; |
63 | break; | |
64 | default: | |
c4029823 | 65 | MAYBE_SET_EINVAL; |
96aa2d94 RM |
66 | return NULL; |
67 | } | |
dd0ee2e1 UD |
68 | for (i = 1; i < 5; ++i) |
69 | { | |
70 | switch (*++mode) | |
71 | { | |
72 | case '\0': | |
73 | break; | |
74 | case '+': | |
75 | read_write &= _IO_IS_APPENDING; | |
76 | break; | |
77 | case 'm': | |
78 | use_mmap = 1; | |
79 | continue; | |
80 | case 'x': | |
81 | case 'b': | |
82 | default: | |
83 | /* Ignore */ | |
84 | continue; | |
85 | } | |
86 | break; | |
87 | } | |
5f0704b6 | 88 | int fd_flags = __fcntl (fd, F_GETFL); |
2e65ca2b | 89 | if (fd_flags == -1) |
96aa2d94 | 90 | return NULL; |
fd091d3f | 91 | |
2e65ca2b UD |
92 | if (((fd_flags & O_ACCMODE) == O_RDONLY && !(read_write & _IO_NO_WRITES)) |
93 | || ((fd_flags & O_ACCMODE) == O_WRONLY && !(read_write & _IO_NO_READS))) | |
94 | { | |
95 | MAYBE_SET_EINVAL; | |
96 | return NULL; | |
97 | } | |
96aa2d94 RM |
98 | |
99 | /* The May 93 draft of P1003.4/D14.1 (redesignated as 1003.1b) | |
100 | [System Application Program Interface (API) Amendment 1: | |
101 | Realtime Extensions], Rationale B.8.3.3 | |
102 | Open a Stream on a File Descriptor says: | |
103 | ||
7e9c7b9b RM |
104 | Although not explicitly required by POSIX.1, a good |
105 | implementation of append ("a") mode would cause the | |
106 | O_APPEND flag to be set. | |
96aa2d94 RM |
107 | |
108 | (Historical implementations [such as Solaris2] do a one-time | |
109 | seek in fdopen.) | |
110 | ||
111 | However, we do not turn O_APPEND off if the mode is "w" (even | |
112 | though that would seem consistent) because that would be more | |
113 | likely to break historical programs. | |
114 | */ | |
7e9c7b9b | 115 | if ((read_write & _IO_IS_APPENDING) && !(fd_flags & O_APPEND)) |
96aa2d94 | 116 | { |
ae42bbc5 | 117 | do_seek = true; |
5f0704b6 | 118 | if (__fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1) |
96aa2d94 RM |
119 | return NULL; |
120 | } | |
96aa2d94 | 121 | |
edf5b2d7 UD |
122 | new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); |
123 | if (new_f == NULL) | |
96aa2d94 | 124 | return NULL; |
499e7464 | 125 | #ifdef _IO_MTSAFE_IO |
bd355af0 | 126 | new_f->fp.file._lock = &new_f->lock; |
499e7464 | 127 | #endif |
e42637b6 | 128 | _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, |
63fb8f9a | 129 | #if _G_HAVE_MMAP |
dd0ee2e1 UD |
130 | (use_mmap && (read_write & _IO_NO_WRITES)) |
131 | ? &_IO_wfile_jumps_maybe_mmap : | |
e42637b6 | 132 | #endif |
15a686af | 133 | &_IO_wfile_jumps); |
e42637b6 | 134 | _IO_JUMPS (&new_f->fp) = |
63fb8f9a | 135 | #if _G_HAVE_MMAP |
dd0ee2e1 | 136 | (use_mmap && (read_write & _IO_NO_WRITES)) ? &_IO_file_jumps_maybe_mmap : |
e42637b6 | 137 | #endif |
15a686af | 138 | &_IO_file_jumps; |
db3476af | 139 | _IO_new_file_init_internal (&new_f->fp); |
96aa2d94 | 140 | #if !_IO_UNIFIED_JUMPTABLES |
edf5b2d7 | 141 | new_f->fp.vtable = NULL; |
96aa2d94 | 142 | #endif |
db3476af FW |
143 | /* We only need to record the fd because _IO_file_init_internal will |
144 | have unset the offset. It is important to unset the cached | |
145 | offset because the real offset in the file could change between | |
146 | now and when the handle is activated and we would then mislead | |
147 | ftell into believing that we have a valid offset. */ | |
fa3cd248 | 148 | new_f->fp.file._fileno = fd; |
bd355af0 | 149 | new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE; |
96aa2d94 | 150 | |
817328ee AS |
151 | _IO_mask_flags (&new_f->fp.file, read_write, |
152 | _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); | |
96aa2d94 | 153 | |
ae42bbc5 SP |
154 | /* For append mode, set the file offset to the end of the file if we added |
155 | O_APPEND to the file descriptor flags. Don't update the offset cache | |
156 | though, since the file handle is not active. */ | |
157 | if (do_seek && ((read_write & (_IO_IS_APPENDING | _IO_NO_READS)) | |
158 | == (_IO_IS_APPENDING | _IO_NO_READS))) | |
ea33158c SP |
159 | { |
160 | _IO_off64_t new_pos = _IO_SYSSEEK (&new_f->fp.file, 0, _IO_seek_end); | |
161 | if (new_pos == _IO_pos_BAD && errno != ESPIPE) | |
162 | return NULL; | |
163 | } | |
e42637b6 | 164 | return &new_f->fp.file; |
96aa2d94 | 165 | } |
d18ea0c5 | 166 | libc_hidden_ver (_IO_new_fdopen, _IO_fdopen) |
96aa2d94 | 167 | |
bd355af0 | 168 | strong_alias (_IO_new_fdopen, __new_fdopen) |
fd091d3f UD |
169 | versioned_symbol (libc, _IO_new_fdopen, _IO_fdopen, GLIBC_2_1); |
170 | versioned_symbol (libc, __new_fdopen, fdopen, GLIBC_2_1); |