Mercurial > hg > octave-shane > gnulib-hg
comparison lib/file-has-acl.c @ 16382:cc05dad27529
acl: Don't use GETACLCNT and similar ops, since they are unreliable.
- There were several instances of this pattern:
for (;;) {
n = acl (f, GETACLCNT, 0, NULL);
[ allocate an array A of size N ]
if (acl (f, GETACL, n, a) == n)
break;
}
This loop might never terminate if some other process is constantly
manipulating the file's ACL. The loop should be rewritten to
terminate.
- The acl (... GETACLNT ...) call is merely an optimization; its value
is merely a hint as to how big to make the array. A better
optimization is to avoid the acl (... GETACLNT ...) call entirely,
and just guess a reasonably-big size, growing the size and trying
again if it's not large enough. This guarantees termination, and
saves a system call.
* lib/acl-internal.h: Include <limits.h>.
(MIN, SIZE_MAX): New macros.
* lib/file-has-acl.c (file_has_acl) [Solaris]: Read the entries into
a stack-allocated buffer, and use malloc if it does not fit. Don't
use GETACLCNT.
* lib/set-mode-acl.c (qset_acl) [Solaris]: Likewise.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Mon, 20 Feb 2012 01:12:06 +0100 |
parents | fc5c37ccbece |
children | 531aa00a1e80 |
comparison
equal
deleted
inserted
replaced
16381:fc5c37ccbece | 16382:cc05dad27529 |
---|---|
554 } | 554 } |
555 if (ret < 0) | 555 if (ret < 0) |
556 return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; | 556 return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; |
557 return ret; | 557 return ret; |
558 | 558 |
559 # elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ | 559 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ |
560 | 560 |
561 # if defined ACL_NO_TRIVIAL | 561 # if defined ACL_NO_TRIVIAL |
562 | 562 |
563 /* Solaris 10 (newer version), which has additional API declared in | 563 /* Solaris 10 (newer version), which has additional API declared in |
564 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, | 564 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, |
568 # else /* Solaris, Cygwin, general case */ | 568 # else /* Solaris, Cygwin, general case */ |
569 | 569 |
570 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions | 570 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions |
571 of Unixware. The acl() call returns the access and default ACL both | 571 of Unixware. The acl() call returns the access and default ACL both |
572 at once. */ | 572 at once. */ |
573 int count; | |
574 { | 573 { |
575 aclent_t *entries; | 574 /* Initially, try to read the entries into a stack-allocated buffer. |
575 Use malloc if it does not fit. */ | |
576 enum | |
577 { | |
578 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */ | |
579 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t)) | |
580 }; | |
581 aclent_t buf[alloc_init]; | |
582 size_t alloc = alloc_init; | |
583 aclent_t *entries = buf; | |
584 aclent_t *malloced = NULL; | |
585 int count; | |
576 | 586 |
577 for (;;) | 587 for (;;) |
578 { | 588 { |
579 count = acl (name, GETACLCNT, 0, NULL); | 589 count = acl (name, GETACL, alloc, entries); |
580 | 590 if (count < 0 && errno == ENOSPC) |
581 if (count < 0) | |
582 { | 591 { |
583 if (errno == ENOSYS || errno == ENOTSUP) | 592 /* Increase the size of the buffer. */ |
584 break; | 593 free (malloced); |
585 else | 594 if (alloc > alloc_max / 2) |
586 return -1; | 595 { |
596 errno = ENOMEM; | |
597 return -1; | |
598 } | |
599 alloc = 2 * alloc; /* <= alloc_max */ | |
600 entries = malloced = | |
601 (aclent_t *) malloc (alloc * sizeof (aclent_t)); | |
602 if (entries == NULL) | |
603 { | |
604 errno = ENOMEM; | |
605 return -1; | |
606 } | |
607 continue; | |
587 } | 608 } |
588 | 609 break; |
589 if (count == 0) | 610 } |
590 break; | 611 if (count < 0) |
591 | 612 { |
613 if (errno == ENOSYS || errno == ENOTSUP) | |
614 ; | |
615 else | |
616 { | |
617 int saved_errno = errno; | |
618 free (malloced); | |
619 errno = saved_errno; | |
620 return -1; | |
621 } | |
622 } | |
623 else if (count == 0) | |
624 ; | |
625 else | |
626 { | |
592 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin | 627 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin |
593 returns only 3 entries for files with no ACL. But this is safe: | 628 returns only 3 entries for files with no ACL. But this is safe: |
594 If there are more than 4 entries, there cannot be only the | 629 If there are more than 4 entries, there cannot be only the |
595 "user::", "group::", "other:", and "mask:" entries. */ | 630 "user::", "group::", "other:", and "mask:" entries. */ |
596 if (count > 4) | 631 if (count > 4) |
597 return 1; | |
598 | |
599 entries = (aclent_t *) malloc (count * sizeof (aclent_t)); | |
600 if (entries == NULL) | |
601 { | 632 { |
602 errno = ENOMEM; | 633 free (malloced); |
603 return -1; | 634 return 1; |
604 } | 635 } |
605 if (acl (name, GETACL, count, entries) == count) | 636 |
637 if (acl_nontrivial (count, entries)) | |
606 { | 638 { |
607 if (acl_nontrivial (count, entries)) | 639 free (malloced); |
608 { | 640 return 1; |
609 free (entries); | |
610 return 1; | |
611 } | |
612 free (entries); | |
613 break; | |
614 } | 641 } |
615 /* Huh? The number of ACL entries changed since the last call. | |
616 Repeat. */ | |
617 free (entries); | |
618 } | 642 } |
643 free (malloced); | |
619 } | 644 } |
620 | 645 |
621 # ifdef ACE_GETACL | 646 # ifdef ACE_GETACL |
622 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 | 647 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 |
623 file systems (whereas the other ones are used in UFS file systems). */ | 648 file systems (whereas the other ones are used in UFS file systems). */ |
624 { | 649 { |
625 ace_t *entries; | 650 /* Initially, try to read the entries into a stack-allocated buffer. |
651 Use malloc if it does not fit. */ | |
652 enum | |
653 { | |
654 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */ | |
655 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t)) | |
656 }; | |
657 ace_t buf[alloc_init]; | |
658 size_t alloc = alloc_init; | |
659 ace_t *entries = buf; | |
660 ace_t *malloced = NULL; | |
661 int count; | |
626 | 662 |
627 for (;;) | 663 for (;;) |
628 { | 664 { |
629 int ret; | 665 count = acl (name, ACE_GETACL, alloc, entries); |
630 | 666 if (count < 0 && errno == ENOSPC) |
631 count = acl (name, ACE_GETACLCNT, 0, NULL); | |
632 | |
633 if (count < 0) | |
634 { | 667 { |
635 if (errno == ENOSYS || errno == EINVAL) | 668 /* Increase the size of the buffer. */ |
636 break; | 669 free (malloced); |
637 else | 670 if (alloc > alloc_max / 2) |
638 return -1; | 671 { |
672 errno = ENOMEM; | |
673 return -1; | |
674 } | |
675 alloc = 2 * alloc; /* <= alloc_max */ | |
676 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); | |
677 if (entries == NULL) | |
678 { | |
679 errno = ENOMEM; | |
680 return -1; | |
681 } | |
682 continue; | |
639 } | 683 } |
640 | 684 break; |
641 if (count == 0) | 685 } |
642 break; | 686 if (count < 0) |
643 | 687 { |
688 if (errno == ENOSYS || errno == EINVAL) | |
689 ; | |
690 else | |
691 { | |
692 int saved_errno = errno; | |
693 free (malloced); | |
694 errno = saved_errno; | |
695 return -1; | |
696 } | |
697 } | |
698 else if (count == 0) | |
699 ; | |
700 else | |
701 { | |
644 /* In the old (original Solaris 10) convention: | 702 /* In the old (original Solaris 10) convention: |
645 If there are more than 3 entries, there cannot be only the | 703 If there are more than 3 entries, there cannot be only the |
646 ACE_OWNER, ACE_GROUP, ACE_OTHER entries. | 704 ACE_OWNER, ACE_GROUP, ACE_OTHER entries. |
647 In the newer Solaris 10 and Solaris 11 convention: | 705 In the newer Solaris 10 and Solaris 11 convention: |
648 If there are more than 6 entries, there cannot be only the | 706 If there are more than 6 entries, there cannot be only the |
649 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with | 707 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with |
650 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with | 708 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with |
651 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ | 709 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ |
652 if (count > 6) | 710 if (count > 6) |
653 return 1; | |
654 | |
655 entries = (ace_t *) malloc (count * sizeof (ace_t)); | |
656 if (entries == NULL) | |
657 { | 711 { |
658 errno = ENOMEM; | 712 free (malloced); |
659 return -1; | 713 return 1; |
660 } | 714 } |
661 ret = acl (name, ACE_GETACL, count, entries); | 715 |
662 if (ret < 0) | 716 if (acl_ace_nontrivial (count, entries)) |
663 { | 717 { |
664 free (entries); | 718 free (malloced); |
665 if (errno == ENOSYS || errno == EINVAL) | 719 return 1; |
666 break; | |
667 else | |
668 return -1; | |
669 } | 720 } |
670 if (ret == count) | |
671 { | |
672 if (acl_ace_nontrivial (count, entries)) | |
673 { | |
674 free (entries); | |
675 return 1; | |
676 } | |
677 free (entries); | |
678 break; | |
679 } | |
680 /* Huh? The number of ACL entries changed since the last call. | |
681 Repeat. */ | |
682 free (entries); | |
683 } | 721 } |
722 free (malloced); | |
684 } | 723 } |
685 # endif | 724 # endif |
686 | 725 |
687 return 0; | 726 return 0; |
688 # endif | 727 # endif |