diff options
Diffstat (limited to 'gl/fcntl.c')
| -rw-r--r-- | gl/fcntl.c | 185 |
1 files changed, 106 insertions, 79 deletions
| @@ -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 | |||
| 549 | static int | 546 | static int |
| 550 | klibc_fcntl (int fd, int action, /* arg */...) | 547 | klibc_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 | |||
| 579 | static int | ||
| 580 | klibc_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 | ||
