OpenCoverage

fcntl.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/gnulib/lib/fcntl.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* Provide file descriptor control.-
2-
3 Copyright (C) 2009-2018 Free Software Foundation, Inc.-
4-
5 This program is free software: you can redistribute it and/or modify-
6 it under the terms of the GNU General Public License as published by-
7 the Free Software Foundation; either version 3 of the License, or-
8 (at your option) any later version.-
9-
10 This program is distributed in the hope that it will be useful,-
11 but WITHOUT ANY WARRANTY; without even the implied warranty of-
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-
13 GNU General Public License for more details.-
14-
15 You should have received a copy of the GNU General Public License-
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */-
17-
18/* Written by Eric Blake <ebb9@byu.net>. */-
19-
20#include <config.h>-
21-
22/* Specification. */-
23#include <fcntl.h>-
24-
25#include <errno.h>-
26#include <limits.h>-
27#include <stdarg.h>-
28#include <unistd.h>-
29-
30#if !HAVE_FCNTL-
31# define rpl_fcntl fcntl-
32#endif-
33#undef fcntl-
34-
35#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__-
36/* Get declarations of the native Windows API functions. */-
37# define WIN32_LEAN_AND_MEAN-
38# include <windows.h>-
39-
40/* Get _get_osfhandle. */-
41# if GNULIB_MSVC_NOTHROW-
42# include "msvc-nothrow.h"-
43# else-
44# include <io.h>-
45# endif-
46-
47/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */-
48# define OPEN_MAX_MAX 0x10000-
49-
50/* Duplicate OLDFD into the first available slot of at least NEWFD,-
51 which must be positive, with FLAGS determining whether the duplicate-
52 will be inheritable. */-
53static int-
54dupfd (int oldfd, int newfd, int flags)-
55{-
56 /* Mingw has no way to create an arbitrary fd. Iterate until all-
57 file descriptors less than newfd are filled up. */-
58 HANDLE curr_process = GetCurrentProcess ();-
59 HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);-
60 unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];-
61 unsigned int fds_to_close_bound = 0;-
62 int result;-
63 BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;-
64 int mode;-
65-
66 if (newfd < 0 || getdtablesize () <= newfd)-
67 {-
68 errno = EINVAL;-
69 return -1;-
70 }-
71 if (old_handle == INVALID_HANDLE_VALUE-
72 || (mode = setmode (oldfd, O_BINARY)) == -1)-
73 {-
74 /* oldfd is not open, or is an unassigned standard file-
75 descriptor. */-
76 errno = EBADF;-
77 return -1;-
78 }-
79 setmode (oldfd, mode);-
80 flags |= mode;-
81-
82 for (;;)-
83 {-
84 HANDLE new_handle;-
85 int duplicated_fd;-
86 unsigned int index;-
87-
88 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */-
89 old_handle, /* SourceHandle */-
90 curr_process, /* TargetProcessHandle */-
91 (PHANDLE) &new_handle, /* TargetHandle */-
92 (DWORD) 0, /* DesiredAccess */-
93 inherit, /* InheritHandle */-
94 DUPLICATE_SAME_ACCESS)) /* Options */-
95 {-
96 switch (GetLastError ())-
97 {-
98 case ERROR_TOO_MANY_OPEN_FILES:-
99 errno = EMFILE;-
100 break;-
101 case ERROR_INVALID_HANDLE:-
102 case ERROR_INVALID_TARGET_HANDLE:-
103 case ERROR_DIRECT_ACCESS_HANDLE:-
104 errno = EBADF;-
105 break;-
106 case ERROR_INVALID_PARAMETER:-
107 case ERROR_INVALID_FUNCTION:-
108 case ERROR_INVALID_ACCESS:-
109 errno = EINVAL;-
110 break;-
111 default:-
112 errno = EACCES;-
113 break;-
114 }-
115 result = -1;-
116 break;-
117 }-
118 duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);-
119 if (duplicated_fd < 0)-
120 {-
121 CloseHandle (new_handle);-
122 result = -1;-
123 break;-
124 }-
125 if (newfd <= duplicated_fd)-
126 {-
127 result = duplicated_fd;-
128 break;-
129 }-
130-
131 /* Set the bit duplicated_fd in fds_to_close[]. */-
132 index = (unsigned int) duplicated_fd / CHAR_BIT;-
133 if (fds_to_close_bound <= index)-
134 {-
135 if (sizeof fds_to_close <= index)-
136 /* Need to increase OPEN_MAX_MAX. */-
137 abort ();-
138 memset (fds_to_close + fds_to_close_bound, '\0',-
139 index + 1 - fds_to_close_bound);-
140 fds_to_close_bound = index + 1;-
141 }-
142 fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);-
143 }-
144-
145 /* Close the previous fds that turned out to be too small. */-
146 {-
147 int saved_errno = errno;-
148 unsigned int duplicated_fd;-
149-
150 for (duplicated_fd = 0;-
151 duplicated_fd < fds_to_close_bound * CHAR_BIT;-
152 duplicated_fd++)-
153 if ((fds_to_close[duplicated_fd / CHAR_BIT]-
154 >> (duplicated_fd % CHAR_BIT))-
155 & 1)-
156 close (duplicated_fd);-
157-
158 errno = saved_errno;-
159 }-
160-
161# if REPLACE_FCHDIR-
162 if (0 <= result)-
163 result = _gl_register_dup (oldfd, result);-
164# endif-
165 return result;-
166}-
167#endif /* W32 */-
168-
169#ifdef __KLIBC__-
170-
171# define INCL_DOS-
172# include <os2.h>-
173-
174static int-
175klibc_fcntl (int fd, int action, /* arg */...)-
176{-
177 va_list arg_ptr;-
178 int arg;-
179 struct stat sbuf;-
180 int result = -1;-
181-
182 va_start (arg_ptr, action);-
183 arg = va_arg (arg_ptr, int);-
184 result = fcntl (fd, action, arg);-
185 /* EPERM for F_DUPFD, ENOTSUP for others */-
186 if (result == -1 && (errno == EPERM || errno == ENOTSUP)-
187 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))-
188 {-
189 ULONG ulMode;-
190-
191 switch (action)-
192 {-
193 case F_DUPFD:-
194 /* Find available fd */-
195 while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)-
196 arg++;-
197-
198 result = dup2 (fd, arg);-
199 break;-
200-
201 /* Using underlying APIs is right ? */-
202 case F_GETFD:-
203 if (DosQueryFHState (fd, &ulMode))-
204 break;-
205-
206 result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;-
207 break;-
208-
209 case F_SETFD:-
210 if (arg & ~FD_CLOEXEC)-
211 break;-
212-
213 if (DosQueryFHState (fd, &ulMode))-
214 break;-
215-
216 if (arg & FD_CLOEXEC)-
217 ulMode |= OPEN_FLAGS_NOINHERIT;-
218 else-
219 ulMode &= ~OPEN_FLAGS_NOINHERIT;-
220-
221 /* Filter supported flags. */-
222 ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR-
223 | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);-
224-
225 if (DosSetFHState (fd, ulMode))-
226 break;-
227-
228 result = 0;-
229 break;-
230-
231 case F_GETFL:-
232 result = 0;-
233 break;-
234-
235 case F_SETFL:-
236 if (arg != 0)-
237 break;-
238-
239 result = 0;-
240 break;-
241-
242 default :-
243 errno = EINVAL;-
244 break;-
245 }-
246 }-
247-
248 va_end (arg_ptr);-
249-
250 return result;-
251}-
252-
253# define fcntl klibc_fcntl-
254#endif-
255-
256/* Perform the specified ACTION on the file descriptor FD, possibly-
257 using the argument ARG further described below. This replacement-
258 handles the following actions, and forwards all others on to the-
259 native fcntl. An unrecognized ACTION returns -1 with errno set to-
260 EINVAL.-
261-
262 F_DUPFD - duplicate FD, with int ARG being the minimum target fd.-
263 If successful, return the duplicate, which will be inheritable;-
264 otherwise return -1 and set errno.-
265-
266 F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum-
267 target fd. If successful, return the duplicate, which will not be-
268 inheritable; otherwise return -1 and set errno.-
269-
270 F_GETFD - ARG need not be present. If successful, return a-
271 non-negative value containing the descriptor flags of FD (only-
272 FD_CLOEXEC is portable, but other flags may be present); otherwise-
273 return -1 and set errno. */-
274-
275int-
276rpl_fcntl (int fd, int action, /* arg */...)-
277{-
278 va_list arg;-
279 int result = -1;-
280 va_start (arg, action);-
281 switch (action)-
282 {-
283-
284#if !HAVE_FCNTL-
285 case F_DUPFD:-
286 {-
287 int target = va_arg (arg, int);-
288 result = dupfd (fd, target, 0);-
289 break;-
290 }-
291#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR-
292 case F_DUPFD:-
293 {-
294 int target = va_arg (arg, int);-
295 /* Detect invalid target; needed for cygwin 1.5.x. */-
296 if (target < 0 || getdtablesize () <= target)-
297 errno = EINVAL;-
298 else-
299 {-
300 /* Haiku alpha 2 loses fd flags on original. */-
301 int flags = fcntl (fd, F_GETFD);-
302 if (flags < 0)-
303 {-
304 result = -1;-
305 break;-
306 }-
307 result = fcntl (fd, action, target);-
308 if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)-
309 {-
310 int saved_errno = errno;-
311 close (result);-
312 result = -1;-
313 errno = saved_errno;-
314 }-
315# if REPLACE_FCHDIR-
316 if (0 <= result)-
317 result = _gl_register_dup (fd, result);-
318# endif-
319 }-
320 break;-
321 } /* F_DUPFD */-
322#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */-
323-
324 case F_DUPFD_CLOEXEC:
executed 61028 times by 6 tests: case 1030 :
Executed by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
61028
325 {-
326 int target = va_arg (arg, int);-
327-
328#if !HAVE_FCNTL-
329 result = dupfd (fd, target, O_CLOEXEC);-
330 break;-
331#else /* HAVE_FCNTL */-
332 /* Try the system call first, if the headers claim it exists-
333 (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we-
334 may be running with a glibc that has the macro but with an-
335 older kernel that does not support it. Cache the-
336 information on whether the system call really works, but-
337 avoid caching failure if the corresponding F_DUPFD fails-
338 for any reason. 0 = unknown, 1 = yes, -1 = no. */-
339 static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
dead code: -1
-
340 if (0 <= have_dupfd_cloexec)
0 <= have_dupfd_cloexecDescription
TRUEevaluated 61028 times by 6 tests
Evaluated by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
FALSEnever evaluated
0-61028
341 {-
342 result = fcntl (fd, action, target);-
343 if (0 <= result || errno != EINVAL)
0 <= resultDescription
TRUEevaluated 61028 times by 6 tests
Evaluated by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
FALSEnever evaluated
(*__errno_location ()) != 22Description
TRUEnever evaluated
FALSEnever evaluated
0-61028
344 {-
345 have_dupfd_cloexec = 1;-
346# if REPLACE_FCHDIR-
347 if (0 <= result)-
348 result = _gl_register_dup (fd, result);-
349# endif-
350 }
executed 61028 times by 6 tests: end of block
Executed by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
61028
351 else-
352 {-
353 result = rpl_fcntl (fd, F_DUPFD, target);-
354 if (result < 0)
result < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
355 break;
never executed: break;
0
356 have_dupfd_cloexec = -1;-
357 }
never executed: end of block
0
358 }-
359 else-
360 result = rpl_fcntl (fd, F_DUPFD, target);
never executed: result = rpl_fcntl (fd, 0 , target);
0
361 if (0 <= result && have_dupfd_cloexec == -1)
0 <= resultDescription
TRUEevaluated 61028 times by 6 tests
Evaluated by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
FALSEnever evaluated
have_dupfd_cloexec == -1Description
TRUEnever evaluated
FALSEevaluated 61028 times by 6 tests
Evaluated by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
0-61028
362 {-
363 int flags = fcntl (result, F_GETFD);-
364 if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
flags < 0Description
TRUEnever evaluated
FALSEnever evaluated
fcntl (result,...gs | 1 ) == -1Description
TRUEnever evaluated
FALSEnever evaluated
0
365 {-
366 int saved_errno = errno;-
367 close (result);-
368 errno = saved_errno;-
369 result = -1;-
370 }
never executed: end of block
0
371 }
never executed: end of block
0
372 break;
executed 61028 times by 6 tests: break;
Executed by:
  • chgrp
  • chmod
  • chown
  • du
  • mv
  • rm
61028
373#endif /* HAVE_FCNTL */-
374 } /* F_DUPFD_CLOEXEC */-
375-
376#if !HAVE_FCNTL-
377 case F_GETFD:-
378 {-
379# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__-
380 HANDLE handle = (HANDLE) _get_osfhandle (fd);-
381 DWORD flags;-
382 if (handle == INVALID_HANDLE_VALUE-
383 || GetHandleInformation (handle, &flags) == 0)-
384 errno = EBADF;-
385 else-
386 result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;-
387# else /* !W32 */-
388 /* Use dup2 to reject invalid file descriptors. No way to-
389 access this information, so punt. */-
390 if (0 <= dup2 (fd, fd))-
391 result = 0;-
392# endif /* !W32 */-
393 break;-
394 } /* F_GETFD */-
395#endif /* !HAVE_FCNTL */-
396-
397 /* Implementing F_SETFD on mingw is not trivial - there is no-
398 API for changing the O_NOINHERIT bit on an fd, and merely-
399 changing the HANDLE_FLAG_INHERIT bit on the underlying handle-
400 can lead to odd state. It may be possible by duplicating the-
401 handle, using _open_osfhandle with the right flags, then-
402 using dup2 to move the duplicate onto the original, but that-
403 is not supported for now. */-
404-
405 default:
executed 115 times by 6 tests: default:
Executed by:
  • cp
  • dd
  • shred
  • sync
  • tac
  • tail
115
406 {-
407#if HAVE_FCNTL-
408 void *p = va_arg (arg, void *);-
409 result = fcntl (fd, action, p);-
410#else-
411 errno = EINVAL;-
412#endif-
413 break;
executed 115 times by 6 tests: break;
Executed by:
  • cp
  • dd
  • shred
  • sync
  • tac
  • tail
115
414 }-
415 }-
416 va_end (arg);-
417 return result;
executed 61143 times by 12 tests: return result;
Executed by:
  • chgrp
  • chmod
  • chown
  • cp
  • dd
  • du
  • mv
  • rm
  • shred
  • sync
  • tac
  • tail
61143
418}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2