summaryrefslogtreecommitdiffstats
path: root/gl/fcntl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/fcntl.c')
-rw-r--r--gl/fcntl.c185
1 files changed, 106 insertions, 79 deletions
diff --git a/gl/fcntl.c b/gl/fcntl.c
index ecb18e50..1c0e52d2 100644
--- a/gl/fcntl.c
+++ b/gl/fcntl.c
@@ -1,6 +1,6 @@
1/* Provide file descriptor control. 1/* Provide file descriptor control.
2 2
3 Copyright (C) 2009-2025 Free Software Foundation, Inc. 3 Copyright (C) 2009-2026 Free Software Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as 6 it under the terms of the GNU Lesser General Public License as
@@ -30,6 +30,7 @@
30 30
31#ifdef __KLIBC__ 31#ifdef __KLIBC__
32# include <emx/io.h> 32# include <emx/io.h>
33# include <InnoTekLIBC/backend.h>
33#endif 34#endif
34 35
35#if defined _WIN32 && ! defined __CYGWIN__ 36#if defined _WIN32 && ! defined __CYGWIN__
@@ -55,19 +56,15 @@ dupfd (int oldfd, int newfd, int flags)
55{ 56{
56 /* Mingw has no way to create an arbitrary fd. Iterate until all 57 /* Mingw has no way to create an arbitrary fd. Iterate until all
57 file descriptors less than newfd are filled up. */ 58 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 59
66 if (newfd < 0 || getdtablesize () <= newfd) 60 if (newfd < 0 || getdtablesize () <= newfd)
67 { 61 {
68 errno = EINVAL; 62 errno = EINVAL;
69 return -1; 63 return -1;
70 } 64 }
65
66 HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
67 int mode;
71 if (old_handle == INVALID_HANDLE_VALUE 68 if (old_handle == INVALID_HANDLE_VALUE
72 || (mode = _setmode (oldfd, O_BINARY)) == -1) 69 || (mode = _setmode (oldfd, O_BINARY)) == -1)
73 { 70 {
@@ -79,6 +76,11 @@ dupfd (int oldfd, int newfd, int flags)
79 _setmode (oldfd, mode); 76 _setmode (oldfd, mode);
80 flags |= mode; 77 flags |= mode;
81 78
79 HANDLE curr_process = GetCurrentProcess ();
80 BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
81 unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
82 unsigned int fds_to_close_bound = 0;
83 int result;
82 for (;;) 84 for (;;)
83 { 85 {
84 HANDLE new_handle; 86 HANDLE new_handle;
@@ -145,9 +147,8 @@ dupfd (int oldfd, int newfd, int flags)
145 /* Close the previous fds that turned out to be too small. */ 147 /* Close the previous fds that turned out to be too small. */
146 { 148 {
147 int saved_errno = errno; 149 int saved_errno = errno;
148 unsigned int duplicated_fd;
149 150
150 for (duplicated_fd = 0; 151 for (unsigned int duplicated_fd = 0;
151 duplicated_fd < fds_to_close_bound * CHAR_BIT; 152 duplicated_fd < fds_to_close_bound * CHAR_BIT;
152 duplicated_fd++) 153 duplicated_fd++)
153 if ((fds_to_close[duplicated_fd / CHAR_BIT] 154 if ((fds_to_close[duplicated_fd / CHAR_BIT]
@@ -205,8 +206,9 @@ fcntl (int fd, int action, /* arg */...)
205#endif 206#endif
206{ 207{
207 va_list arg; 208 va_list arg;
208 int result = -1;
209 va_start (arg, action); 209 va_start (arg, action);
210
211 int result = -1;
210 switch (action) 212 switch (action)
211 { 213 {
212 case F_DUPFD: 214 case F_DUPFD:
@@ -375,12 +377,6 @@ fcntl (int fd, int action, /* arg */...)
375 #ifdef F_NOTIFY /* Linux */ 377 #ifdef F_NOTIFY /* Linux */
376 case F_NOTIFY: 378 case F_NOTIFY:
377 #endif 379 #endif
378 #ifdef F_OPLKACK /* IRIX */
379 case F_OPLKACK:
380 #endif
381 #ifdef F_OPLKREG /* IRIX */
382 case F_OPLKREG:
383 #endif
384 #ifdef F_RDAHEAD /* macOS */ 380 #ifdef F_RDAHEAD /* macOS */
385 case F_RDAHEAD: 381 case F_RDAHEAD:
386 #endif 382 #endif
@@ -438,7 +434,9 @@ fcntl (int fd, int action, /* arg */...)
438 break; 434 break;
439 } 435 }
440 } 436 }
437
441 va_end (arg); 438 va_end (arg);
439
442 return result; 440 return result;
443} 441}
444 442
@@ -545,86 +543,115 @@ rpl_fcntl_DUPFD_CLOEXEC (int fd, int target)
545#undef fcntl 543#undef fcntl
546 544
547#ifdef __KLIBC__ 545#ifdef __KLIBC__
548
549static int 546static int
550klibc_fcntl (int fd, int action, /* arg */...) 547klibc_dupdirfd (int fd, int minfd)
551{ 548{
552 va_list arg_ptr; 549 int tempfd = open ("NUL", O_RDONLY);
553 int arg; 550 if (tempfd == -1)
554 struct stat sbuf; 551 return -1;
555 int result;
556 552
557 va_start (arg_ptr, action); 553 if (tempfd >= minfd)
558 arg = va_arg (arg_ptr, int);
559 result = fcntl (fd, action, arg);
560 /* EPERM for F_DUPFD, ENOTSUP for others */
561 if (result == -1 && (errno == EPERM || errno == ENOTSUP)
562 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
563 { 554 {
564 PLIBCFH pFH; 555 close (tempfd);
565 unsigned fFlags;
566 556
567 switch (action) 557 char path[_MAX_PATH];
568 { 558 if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
569 case F_DUPFD: 559 return -1;
570 /* Find available fd */
571 while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
572 arg++;
573 560
574 result = dup2 (fd, arg); 561 int dupfd = open (path, O_RDONLY);
575 break; 562 if (dupfd == -1)
563 return -1;
576 564
577 case F_GETFD: 565 if (dupfd >= minfd)
578 pFH = __libc_FH (fd); 566 return dupfd;
579 if (!pFH)
580 {
581 errno = EBADF;
582 break;
583 }
584 567
585 result = (pFH->fFlags & ((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT ) 568 /* Lower FD was closed by other threads. Fill again. */
586 | O_NOINHERIT)) ? FD_CLOEXEC : 0; 569 tempfd = dupfd;
587 break; 570 }
588 571
589 case F_SETFD: 572 int dupfd = klibc_dupdirfd (fd, minfd);
590 if (arg & ~FD_CLOEXEC)
591 break;
592 573
593 pFH = __libc_FH (fd); 574 close (tempfd);
594 if (!pFH) 575
576 return dupfd;
577}
578
579static int
580klibc_fcntl (int fd, int action, /* arg */...)
581{
582 va_list arg_ptr;
583 va_start (arg_ptr, action);
584
585 int arg = va_arg (arg_ptr, int);
586 int result = fcntl (fd, action, arg);
587 /* EPERM for F_DUPFD, ENOTSUP for others */
588 if (result == -1 && (errno == EPERM || errno == ENOTSUP))
589 {
590 struct stat sbuf;
591 if (!fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
592 {
593 switch (action)
595 { 594 {
596 errno = EBADF; 595 case F_DUPFD:
596 result = klibc_dupdirfd (fd, arg);
597 break; 597 break;
598 }
599 598
600 fFlags = pFH->fFlags; 599 case F_GETFD:
601 if (arg & FD_CLOEXEC) 600 {
602 fFlags |= (FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT; 601 PLIBCFH pFH = __libc_FH (fd);
603 else 602 if (!pFH)
604 fFlags &= ~((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT); 603 {
604 errno = EBADF;
605 break;
606 }
607
608 result = (pFH->fFlags & ((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT )
609 | O_NOINHERIT)) ? FD_CLOEXEC : 0;
610 }
611 break;
605 612
606 result = __libc_FHSetFlags (pFH, fd, fFlags); 613 case F_SETFD:
607 if (result < 0) 614 {
608 { 615 if (arg & ~FD_CLOEXEC)
609 errno = -result; 616 break;
610 result = -1; 617
611 } 618 PLIBCFH pFH = __libc_FH (fd);
612 break; 619 if (!pFH)
620 {
621 errno = EBADF;
622 break;
623 }
624
625 unsigned fFlags = pFH->fFlags;
626 if (arg & FD_CLOEXEC)
627 fFlags |= (FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT;
628 else
629 fFlags &= ~((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT);
630
631 result = __libc_FHSetFlags (pFH, fd, fFlags);
632 if (result < 0)
633 {
634 errno = -result;
635 result = -1;
636 }
637 }
638 break;
613 639
614 case F_GETFL: 640 case F_GETFL:
615 result = 0; 641 result = 0;
616 break; 642 break;
617 643
618 case F_SETFL: 644 case F_SETFL:
619 if (arg != 0) 645 if (arg != 0)
620 break; 646 break;
621 647
622 result = 0; 648 result = 0;
623 break; 649 break;
624 650
625 default: 651 default:
626 errno = EINVAL; 652 errno = EINVAL;
627 break; 653 break;
654 }
628 } 655 }
629 } 656 }
630 657