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