This source file includes following definitions.
- dupfd
- rpl_fcntl_DUPFD
- rpl_fcntl_DUPFD_CLOEXEC
- klibc_fcntl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22
23 #include <fcntl.h>
24
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30
31 #ifdef __KLIBC__
32 # define INCL_DOS
33 # include <os2.h>
34 #endif
35
36 #if defined _WIN32 && ! defined __CYGWIN__
37
38 # define WIN32_LEAN_AND_MEAN
39 # include <windows.h>
40
41
42 # if GNULIB_MSVC_NOTHROW
43 # include "msvc-nothrow.h"
44 # else
45 # include <io.h>
46 # endif
47
48
49 # define OPEN_MAX_MAX 0x10000
50
51
52
53
54 static int
55 dupfd (int oldfd, int newfd, int flags)
56 {
57
58
59 HANDLE curr_process = GetCurrentProcess ();
60 HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
61 unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
62 unsigned int fds_to_close_bound = 0;
63 int result;
64 BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
65 int mode;
66
67 if (newfd < 0 || getdtablesize () <= newfd)
68 {
69 errno = EINVAL;
70 return -1;
71 }
72 if (old_handle == INVALID_HANDLE_VALUE
73 || (mode = _setmode (oldfd, O_BINARY)) == -1)
74 {
75
76
77 errno = EBADF;
78 return -1;
79 }
80 _setmode (oldfd, mode);
81 flags |= mode;
82
83 for (;;)
84 {
85 HANDLE new_handle;
86 int duplicated_fd;
87 unsigned int index;
88
89 if (!DuplicateHandle (curr_process,
90 old_handle,
91 curr_process,
92 (PHANDLE) &new_handle,
93 (DWORD) 0,
94 inherit,
95 DUPLICATE_SAME_ACCESS))
96 {
97 switch (GetLastError ())
98 {
99 case ERROR_TOO_MANY_OPEN_FILES:
100 errno = EMFILE;
101 break;
102 case ERROR_INVALID_HANDLE:
103 case ERROR_INVALID_TARGET_HANDLE:
104 case ERROR_DIRECT_ACCESS_HANDLE:
105 errno = EBADF;
106 break;
107 case ERROR_INVALID_PARAMETER:
108 case ERROR_INVALID_FUNCTION:
109 case ERROR_INVALID_ACCESS:
110 errno = EINVAL;
111 break;
112 default:
113 errno = EACCES;
114 break;
115 }
116 result = -1;
117 break;
118 }
119 duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
120 if (duplicated_fd < 0)
121 {
122 CloseHandle (new_handle);
123 result = -1;
124 break;
125 }
126 if (newfd <= duplicated_fd)
127 {
128 result = duplicated_fd;
129 break;
130 }
131
132
133 index = (unsigned int) duplicated_fd / CHAR_BIT;
134 if (fds_to_close_bound <= index)
135 {
136 if (sizeof fds_to_close <= index)
137
138 abort ();
139 memset (fds_to_close + fds_to_close_bound, '\0',
140 index + 1 - fds_to_close_bound);
141 fds_to_close_bound = index + 1;
142 }
143 fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
144 }
145
146
147 {
148 int saved_errno = errno;
149 unsigned int duplicated_fd;
150
151 for (duplicated_fd = 0;
152 duplicated_fd < fds_to_close_bound * CHAR_BIT;
153 duplicated_fd++)
154 if ((fds_to_close[duplicated_fd / CHAR_BIT]
155 >> (duplicated_fd % CHAR_BIT))
156 & 1)
157 close (duplicated_fd);
158
159 errno = saved_errno;
160 }
161
162 # if REPLACE_FCHDIR
163 if (0 <= result)
164 result = _gl_register_dup (oldfd, result);
165 # endif
166 return result;
167 }
168 #endif
169
170
171
172
173 static int rpl_fcntl_DUPFD (int fd, int target);
174
175 static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target);
176 #ifdef __KLIBC__
177
178 static int klibc_fcntl (int fd, int action, ...);
179 #endif
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 int
202 fcntl (int fd, int action, ...)
203 #undef fcntl
204 #ifdef __KLIBC__
205 # define fcntl klibc_fcntl
206 #endif
207 {
208 va_list arg;
209 int result = -1;
210 va_start (arg, action);
211 switch (action)
212 {
213 case F_DUPFD:
214 {
215 int target = va_arg (arg, int);
216 result = rpl_fcntl_DUPFD (fd, target);
217 break;
218 }
219
220 case F_DUPFD_CLOEXEC:
221 {
222 int target = va_arg (arg, int);
223 result = rpl_fcntl_DUPFD_CLOEXEC (fd, target);
224 break;
225 }
226
227 #if !HAVE_FCNTL
228 case F_GETFD:
229 {
230 # if defined _WIN32 && ! defined __CYGWIN__
231 HANDLE handle = (HANDLE) _get_osfhandle (fd);
232 DWORD flags;
233 if (handle == INVALID_HANDLE_VALUE
234 || GetHandleInformation (handle, &flags) == 0)
235 errno = EBADF;
236 else
237 result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
238 # else
239
240
241 if (0 <= dup2 (fd, fd))
242 result = 0;
243 # endif
244 break;
245 }
246 #endif
247
248
249
250
251
252
253
254
255
256 default:
257 {
258 #if HAVE_FCNTL
259 switch (action)
260 {
261 #ifdef F_BARRIERFSYNC
262 case F_BARRIERFSYNC:
263 #endif
264 #ifdef F_CHKCLEAN
265 case F_CHKCLEAN:
266 #endif
267 #ifdef F_CLOSEM
268 case F_CLOSEM:
269 #endif
270 #ifdef F_FLUSH_DATA
271 case F_FLUSH_DATA:
272 #endif
273 #ifdef F_FREEZE_FS
274 case F_FREEZE_FS:
275 #endif
276 #ifdef F_FULLFSYNC
277 case F_FULLFSYNC:
278 #endif
279 #ifdef F_GETCONFINED
280 case F_GETCONFINED:
281 #endif
282 #ifdef F_GETDEFAULTPROTLEVEL
283 case F_GETDEFAULTPROTLEVEL:
284 #endif
285 #ifdef F_GETFD
286 case F_GETFD:
287 #endif
288 #ifdef F_GETFL
289 case F_GETFL:
290 #endif
291 #ifdef F_GETLEASE
292 case F_GETLEASE:
293 #endif
294 #ifdef F_GETNOSIGPIPE
295 case F_GETNOSIGPIPE:
296 #endif
297 #ifdef F_GETOWN
298 case F_GETOWN:
299 #endif
300 #ifdef F_GETPIPE_SZ
301 case F_GETPIPE_SZ:
302 #endif
303 #ifdef F_GETPROTECTIONCLASS
304 case F_GETPROTECTIONCLASS:
305 #endif
306 #ifdef F_GETPROTECTIONLEVEL
307 case F_GETPROTECTIONLEVEL:
308 #endif
309 #ifdef F_GET_SEALS
310 case F_GET_SEALS:
311 #endif
312 #ifdef F_GETSIG
313 case F_GETSIG:
314 #endif
315 #ifdef F_MAXFD
316 case F_MAXFD:
317 #endif
318 #ifdef F_RECYCLE
319 case F_RECYCLE:
320 #endif
321 #ifdef F_SETFIFOENH
322 case F_SETFIFOENH:
323 #endif
324 #ifdef F_THAW_FS
325 case F_THAW_FS:
326 #endif
327
328 result = fcntl (fd, action);
329 break;
330
331 #ifdef F_ADD_SEALS
332 case F_ADD_SEALS:
333 #endif
334 #ifdef F_BADFD
335 case F_BADFD:
336 #endif
337 #ifdef F_CHECK_OPENEVT
338 case F_CHECK_OPENEVT:
339 #endif
340 #ifdef F_DUP2FD
341 case F_DUP2FD:
342 #endif
343 #ifdef F_DUP2FD_CLOEXEC
344 case F_DUP2FD_CLOEXEC:
345 #endif
346 #ifdef F_DUP2FD_CLOFORK
347 case F_DUP2FD_CLOFORK:
348 #endif
349 #ifdef F_DUPFD
350 case F_DUPFD:
351 #endif
352 #ifdef F_DUPFD_CLOEXEC
353 case F_DUPFD_CLOEXEC:
354 #endif
355 #ifdef F_DUPFD_CLOFORK
356 case F_DUPFD_CLOFORK:
357 #endif
358 #ifdef F_GETXFL
359 case F_GETXFL:
360 #endif
361 #ifdef F_GLOBAL_NOCACHE
362 case F_GLOBAL_NOCACHE:
363 #endif
364 #ifdef F_MAKECOMPRESSED
365 case F_MAKECOMPRESSED:
366 #endif
367 #ifdef F_MOVEDATAEXTENTS
368 case F_MOVEDATAEXTENTS:
369 #endif
370 #ifdef F_NOCACHE
371 case F_NOCACHE:
372 #endif
373 #ifdef F_NODIRECT
374 case F_NODIRECT:
375 #endif
376 #ifdef F_NOTIFY
377 case F_NOTIFY:
378 #endif
379 #ifdef F_OPLKACK
380 case F_OPLKACK:
381 #endif
382 #ifdef F_OPLKREG
383 case F_OPLKREG:
384 #endif
385 #ifdef F_RDAHEAD
386 case F_RDAHEAD:
387 #endif
388 #ifdef F_SETBACKINGSTORE
389 case F_SETBACKINGSTORE:
390 #endif
391 #ifdef F_SETCONFINED
392 case F_SETCONFINED:
393 #endif
394 #ifdef F_SETFD
395 case F_SETFD:
396 #endif
397 #ifdef F_SETFL
398 case F_SETFL:
399 #endif
400 #ifdef F_SETLEASE
401 case F_SETLEASE:
402 #endif
403 #ifdef F_SETNOSIGPIPE
404 case F_SETNOSIGPIPE:
405 #endif
406 #ifdef F_SETOWN
407 case F_SETOWN:
408 #endif
409 #ifdef F_SETPIPE_SZ
410 case F_SETPIPE_SZ:
411 #endif
412 #ifdef F_SETPROTECTIONCLASS
413 case F_SETPROTECTIONCLASS:
414 #endif
415 #ifdef F_SETSIG
416 case F_SETSIG:
417 #endif
418 #ifdef F_SINGLE_WRITER
419 case F_SINGLE_WRITER:
420 #endif
421
422 {
423 int x = va_arg (arg, int);
424 result = fcntl (fd, action, x);
425 }
426 break;
427
428 default:
429
430 {
431 void *p = va_arg (arg, void *);
432 result = fcntl (fd, action, p);
433 }
434 break;
435 }
436 #else
437 errno = EINVAL;
438 #endif
439 break;
440 }
441 }
442 va_end (arg);
443 return result;
444 }
445
446 static int
447 rpl_fcntl_DUPFD (int fd, int target)
448 {
449 int result;
450 #if !HAVE_FCNTL
451 result = dupfd (fd, target, 0);
452 #elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
453
454 if (target < 0 || getdtablesize () <= target)
455 {
456 result = -1;
457 errno = EINVAL;
458 }
459 else
460 {
461
462 int flags = fcntl (fd, F_GETFD);
463 if (flags < 0)
464 result = -1;
465 else
466 {
467 result = fcntl (fd, F_DUPFD, target);
468 if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
469 {
470 int saved_errno = errno;
471 close (result);
472 result = -1;
473 errno = saved_errno;
474 }
475 # if REPLACE_FCHDIR
476 if (0 <= result)
477 result = _gl_register_dup (fd, result);
478 # endif
479 }
480 }
481 #else
482 result = fcntl (fd, F_DUPFD, target);
483 #endif
484 return result;
485 }
486
487 static int
488 rpl_fcntl_DUPFD_CLOEXEC (int fd, int target)
489 {
490 int result;
491 #if !HAVE_FCNTL
492 result = dupfd (fd, target, O_CLOEXEC);
493 #else
494 # if defined __NetBSD__ || defined __HAIKU__
495
496
497
498
499
500 # define have_dupfd_cloexec -1
501 # else
502
503
504
505
506
507
508
509 static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
510 if (0 <= have_dupfd_cloexec)
511 {
512 result = fcntl (fd, F_DUPFD_CLOEXEC, target);
513 if (0 <= result || errno != EINVAL)
514 {
515 have_dupfd_cloexec = 1;
516 # if REPLACE_FCHDIR
517 if (0 <= result)
518 result = _gl_register_dup (fd, result);
519 # endif
520 }
521 else
522 {
523 result = rpl_fcntl_DUPFD (fd, target);
524 if (result >= 0)
525 have_dupfd_cloexec = -1;
526 }
527 }
528 else
529 # endif
530 result = rpl_fcntl_DUPFD (fd, target);
531 if (0 <= result && have_dupfd_cloexec == -1)
532 {
533 int flags = fcntl (result, F_GETFD);
534 if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
535 {
536 int saved_errno = errno;
537 close (result);
538 errno = saved_errno;
539 result = -1;
540 }
541 }
542 #endif
543 return result;
544 }
545
546 #undef fcntl
547
548 #ifdef __KLIBC__
549
550 static int
551 klibc_fcntl (int fd, int action, ...)
552 {
553 va_list arg_ptr;
554 int arg;
555 struct stat sbuf;
556 int result;
557
558 va_start (arg_ptr, action);
559 arg = va_arg (arg_ptr, int);
560 result = fcntl (fd, action, arg);
561
562 if (result == -1 && (errno == EPERM || errno == ENOTSUP)
563 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
564 {
565 ULONG ulMode;
566
567 switch (action)
568 {
569 case F_DUPFD:
570
571 while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
572 arg++;
573
574 result = dup2 (fd, arg);
575 break;
576
577
578 case F_GETFD:
579 if (DosQueryFHState (fd, &ulMode))
580 break;
581
582 result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
583 break;
584
585 case F_SETFD:
586 if (arg & ~FD_CLOEXEC)
587 break;
588
589 if (DosQueryFHState (fd, &ulMode))
590 break;
591
592 if (arg & FD_CLOEXEC)
593 ulMode |= OPEN_FLAGS_NOINHERIT;
594 else
595 ulMode &= ~OPEN_FLAGS_NOINHERIT;
596
597
598 ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
599 | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
600
601 if (DosSetFHState (fd, ulMode))
602 break;
603
604 result = 0;
605 break;
606
607 case F_GETFL:
608 result = 0;
609 break;
610
611 case F_SETFL:
612 if (arg != 0)
613 break;
614
615 result = 0;
616 break;
617
618 default:
619 errno = EINVAL;
620 break;
621 }
622 }
623
624 va_end (arg_ptr);
625
626 return result;
627 }
628
629 #endif