bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: coreutils 6.11 on MacOS X 10.5 (2)


From: Bruno Haible
Subject: Re: coreutils 6.11 on MacOS X 10.5 (2)
Date: Mon, 21 Apr 2008 01:11:05 +0200
User-agent: KMail/1.5.4

2) cp/file-perm-race.log can be reproduced like this:

   terminal1$ ../../src/mkfifo fifo
   terminal2$ ../../src/cp -p --copy-contents fifo fifo-copy
   terminal1$ echo foo > fifo
   Now on terminal2:
   ../../src/cp: „fifo“: No such file or directory

Looking in more detail at the "../../src/cp -p --copy-contents fifo fifo-copy"
process:

$ gdb ../../src/cp
0x00004605 in copy_reg (src_name=0xbffff81d "fifo", dst_name=0xbffff822 
"fifo-copy", x=0xbffff6b4, dst_mode=420, omitted_permissions=36, 
new_dst=0xbffff27c, src_sb=0xbffff3c4) at copy.c:340
340       source_desc = open (src_name,
Value returned is $1 = 4
(gdb) next
343       if (source_desc < 0)
(gdb) 
349       if (fstat (source_desc, &src_open_sb) != 0)
(gdb) 
358       if (! SAME_INODE (*src_sb, src_open_sb))
(gdb) 
369       if (! *new_dst)
(gdb) 
426       if (*new_dst)
(gdb) 
428           int open_flags = O_WRONLY | O_CREAT | O_BINARY;
(gdb) 
429           dest_desc = open (dst_name, open_flags | O_EXCL ,
(gdb) 
431           dest_errno = errno;
(gdb) 
442           if (dest_desc < 0 && dest_errno == EEXIST && ! x->move_mode)
(gdb) 
467       if (dest_desc < 0)
(gdb) 
475       if (fstat (dest_desc, &sb) != 0)
(gdb) 
484         off_t n_read_total = 0;
(gdb) 
487         size_t buf_alignment = lcm (getpagesize (), sizeof (word));
(gdb) 
488         size_t buf_alignment_slop = sizeof (word) + buf_alignment - 1;
(gdb) 
489         size_t buf_size = ST_BLKSIZE (sb);
(gdb) 
492         bool last_write_made_hole = false;
(gdb) 
493         bool make_holes = false;
(gdb) 
495         if (S_ISREG (sb.st_mode))
(gdb) 
499             if (x->sparse_mode == SPARSE_ALWAYS)
(gdb) 
507             if (x->sparse_mode == SPARSE_AUTO && S_ISREG 
(src_open_sb.st_mode)
(gdb) 
515         if (! make_holes)
(gdb) 
525             size_t blcm_max = MIN (SIZE_MAX, SSIZE_MAX) - 
buf_alignment_slop;
(gdb) 
527                                       blcm_max);
(gdb) 
530             buf_size = MAX (SMALL_BUF_SIZE, blcm);
(gdb) 
534             if (S_ISREG (src_open_sb.st_mode) && src_open_sb.st_size < 
buf_size)
(gdb) 
540             buf_size += blcm - 1;
(gdb) 
541             buf_size -= buf_size % blcm;
(gdb) 
542             if (buf_size == 0 || blcm_max < buf_size)
(gdb) 
547         buf_alloc = xmalloc (buf_size + buf_alignment_slop);
(gdb) 
548         buf = ptr_align (buf_alloc, buf_alignment);
(gdb) 
552             word *wp = NULL;
(gdb) 
554             ssize_t n_read = read (source_desc, buf, buf_size);
(gdb) 
555             if (n_read < 0)
(gdb) 
565             if (n_read == 0)
(gdb) 
568             n_read_total += n_read;
(gdb) 
570             if (make_holes)
(gdb) 
615             if (!wp)
(gdb) 
617                 size_t n = n_read;
(gdb) 
618                 if (full_write (dest_desc, buf, n) != n)
(gdb) 
624                 last_write_made_hole = false;
(gdb) 
627                 if (n_read != buf_size && S_ISREG (src_open_sb.st_mode))
(gdb) 
552             word *wp = NULL;
(gdb) 
554             ssize_t n_read = read (source_desc, buf, buf_size);
(gdb) 
555             if (n_read < 0)
(gdb) 
565             if (n_read == 0)
(gdb) 
638         if (last_write_made_hole)
(gdb) 
655       if (x->preserve_timestamps)
(gdb) 
658           timespec[0] = get_stat_atime (src_sb);
(gdb) 
659           timespec[1] = get_stat_mtime (src_sb);
(gdb) 
661           if (gl_futimens (dest_desc, dst_name, timespec) != 0)
(gdb) 
672       if (x->preserve_ownership && ! SAME_OWNER_AND_GROUP (*src_sb, sb))
(gdb) 
686       set_author (dst_name, dest_desc, src_sb);
(gdb) 
688       if (x->preserve_mode || x->move_mode)
(gdb) 
690           if (copy_acl (src_name, source_desc, dst_name, dest_desc, 
src_mode) != 0
(gdb) step
copy_acl (src_name=0xbffff81d "fifo", source_desc=4, dst_name=0xbffff822 
"fifo-copy", dest_desc=5, mode=4516) at acl.c:59
59        if (HAVE_ACL_GET_FD && source_desc != -1)
(gdb) next
60          acl = acl_get_fd (source_desc);
(gdb) 
63        if (acl == NULL)
(gdb) 
65            if (ACL_NOT_WELL_SUPPORTED (errno))
(gdb) print *(int*)__error()
$3 = 2
(gdb) next
69                error (0, errno, "%s", quote (src_name));

So the first problem is that acl_get_fd fails with errno = ENOENT, but
ACL_NOT_WELL_SUPPORTED does not recognize this errno. Once this is fixed,
we get a different error message:

$ LC_ALL=C ../../src/cp -p --copy-contents fifo fifo-copy
../../src/cp: setting permissions for `fifo-copy': Invalid argument

The cause is here:

65            if (ACL_NOT_WELL_SUPPORTED (errno))
(gdb) 
66              return set_acl (dst_name, dest_desc, mode);
(gdb) step
set_acl (name=0xbffff822 "fifo-copy", desc=5, mode=4516) at acl.c:316
316       int r = qset_acl (name, desc, mode);
(gdb) step
qset_acl (name=0xbffff822 "fifo-copy", desc=5, mode=4516) at acl.c:220
220           char acl_text[] = "u::---,g::---,o::---";
(gdb) next
222           if (mode & S_IRUSR) acl_text[ 3] = 'r';
(gdb) 
223           if (mode & S_IWUSR) acl_text[ 4] = 'w';
(gdb) 
224           if (mode & S_IXUSR) acl_text[ 5] = 'x';
(gdb) 
225           if (mode & S_IRGRP) acl_text[10] = 'r';
(gdb) 
226           if (mode & S_IWGRP) acl_text[11] = 'w';
(gdb) 
227           if (mode & S_IXGRP) acl_text[12] = 'x';
(gdb) 
228           if (mode & S_IROTH) acl_text[17] = 'r';
(gdb) 
229           if (mode & S_IWOTH) acl_text[18] = 'w';
(gdb) 
230           if (mode & S_IXOTH) acl_text[19] = 'x';
(gdb) 
232           acl = acl_from_text (acl_text);
(gdb) print acl_text
$1 = "u::rw-,g::r--,o::r--"
(gdb) next
233           if (!acl)
(gdb) print acl
$2 = (acl_t) 0x0
(gdb) print *(int*)__error()
$3 = 22
(gdb) next
234             return -1;
(gdb) 
309     }
(gdb) 
set_acl (name=0xbffff822 "fifo-copy", desc=5, mode=4516) at acl.c:317
317       if (r != 0)
(gdb) 
318         error (0, errno, _("setting permissions for %s"), quote (name));

So the second problem is that acl_from_text does not accept the carefully
crafted string in Solaris syntax.

When I have a file like this:

  $ echo > foo.data
  $ /bin/chmod +a "guest allow write" foo.data
  $ /bin/ls -le foo.data
  -rw-r--r--+ 1 bruno  staff  1 Apr 20 23:37 foo.data
   0: group:_guest allow write

then acl_get_fd of the file, followed by acl_to_text, yields a string
consisting of two lines:

  !#acl 1
  group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF000000C9:_guest:201:allow:write

When I change the permissions, e.g.
  $ chmod g+w foo.data
the retrievable ACL is the same. I conclude that the normal permissions
are not part of the ACL, and therefore to reset the ACL there are two
possibilities:
  - Set the ACL to empty. The string "!#acl 1\n" must be used. (The number 1
    is a sort of magic/version number, not the number of ACLs.)
  - Set the ACL to absent. How to do this? I cannot find an 'acl_delete'
    function.

The attached patch fixes the following test failures:

  FAIL: help-version.log
  FAIL: help-version.log (exit: 1)
  FAIL: ginstall
  FAIL: file-perm-race.log
  FAIL: parent-perm-race.log
  FAIL: existing-perm-race.log
  FAIL: backup-dir.log
  FAIL: src-base-dot.log
  FAIL: preserve-2.log
  FAIL: fail-perm.log
  FAIL: cp-parents.log
  FAIL: parent-perm.log (exit: 1)
  FAIL: file-perm-race.log (exit: 1)
  FAIL: parent-perm-race.log (exit: 1)
  FAIL: existing-perm-race.log (exit: 1)
  FAIL: backup-dir.log (exit: 1)
  FAIL: src-base-dot.log (exit: 1)
  FAIL: preserve-2.log (exit: 1)
  FAIL: fail-perm.log (exit: 1)
  FAIL: cp-parents.log (exit: 1)
  FAIL: basic-1.log
  FAIL: create-leading.log
  FAIL: basic-1.log (exit: 1)
  FAIL: create-leading.log (exit: 1)
  FAIL: misc.log
  FAIL: misc.log (exit: 1)

and gladly does not introduce new failures.

But it needs more work to integrate this code with the older POSIX/Solaris
code and to make sure that it does not cause regressions on older MacOS X
versions.

Would you or Paul like to take over from here, or should I provide a safe
patch?

Bruno


*** lib/acl-internal.h.bak      2007-10-17 15:47:25.000000000 +0200
--- lib/acl-internal.h  2008-04-20 23:10:16.000000000 +0200
***************
*** 1,6 ****
  /* Internal implementation of access control lists.
  
!    Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
--- 1,6 ----
  /* Internal implementation of access control lists.
  
!    Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, 
Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 76,82 ****
  #endif
  
  #define ACL_NOT_WELL_SUPPORTED(Err) \
!   ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
  
  /* Define a replacement for acl_entries if needed.  */
  #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
--- 76,82 ----
  #endif
  
  #define ACL_NOT_WELL_SUPPORTED(Err) \
!   ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY 
|| (Err) == ENOENT)
  
  /* Define a replacement for acl_entries if needed.  */
  #if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
*** lib/acl.c.bak       2008-01-31 19:37:18.000000000 +0100
--- lib/acl.c   2008-04-21 00:48:36.000000000 +0200
***************
*** 1,6 ****
  /* acl.c - access control lists
  
!    Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
--- 1,6 ----
  /* acl.c - access control lists
  
!    Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, 
Inc.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 209,272 ****
    acl_t acl;
    int ret;
  
!   if (HAVE_ACL_FROM_MODE)
      {
!       acl = acl_from_mode (mode);
!       if (!acl)
!       return -1;
!     }
!   else
!     {
!       char acl_text[] = "u::---,g::---,o::---";
! 
!       if (mode & S_IRUSR) acl_text[ 3] = 'r';
!       if (mode & S_IWUSR) acl_text[ 4] = 'w';
!       if (mode & S_IXUSR) acl_text[ 5] = 'x';
!       if (mode & S_IRGRP) acl_text[10] = 'r';
!       if (mode & S_IWGRP) acl_text[11] = 'w';
!       if (mode & S_IXGRP) acl_text[12] = 'x';
!       if (mode & S_IROTH) acl_text[17] = 'r';
!       if (mode & S_IWOTH) acl_text[18] = 'w';
!       if (mode & S_IXOTH) acl_text[19] = 'x';
  
        acl = acl_from_text (acl_text);
!       if (!acl)
!       return -1;
!     }
!   if (HAVE_ACL_SET_FD && desc != -1)
!     ret = acl_set_fd (desc, acl);
!   else
!     ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
!   if (ret != 0)
!     {
!       int saved_errno = errno;
!       acl_free (acl);
! 
!       if (ACL_NOT_WELL_SUPPORTED (errno))
        {
!         if (chmod_or_fchmod (name, desc, mode) != 0)
!           saved_errno = errno;
!         else
!           return 0;
        }
-       errno = saved_errno;
-       return -1;
      }
-   else
-     acl_free (acl);
  
!   if (S_ISDIR (mode) && acl_delete_def_file (name))
!     return -1;
! 
!   if (mode & (S_ISUID | S_ISGID | S_ISVTX))
!     {
!       /* We did not call chmod so far, so the special bits have not yet
!          been set.  */
! 
!       if (chmod_or_fchmod (name, desc, mode))
!       return -1;
!     }
!   return 0;
  #else
  
  # if USE_ACL && defined ACL_NO_TRIVIAL
--- 209,242 ----
    acl_t acl;
    int ret;
  
!   if (desc != -1 ? acl_get_fd (desc) : acl_get_file (name, ACL_TYPE_EXTENDED))
      {
!       /* Remove existing ACLs.  */
!       static char acl_text[] = "!#acl 1\n";
  
        acl = acl_from_text (acl_text);
!       if (acl)
        {
!         ret = (desc != -1 ? acl_set_fd (desc, acl) : acl_set_file (name, 
ACL_TYPE_EXTENDED, acl));
!         if (ret != 0)
!           {
!             int saved_errno = errno;
!             acl_free (acl);
! 
!             if (ACL_NOT_WELL_SUPPORTED (errno))
!               {
!                 if (chmod_or_fchmod (name, desc, mode) != 0)
!                   saved_errno = errno;
!                 else
!                   return 0;
!               }
!             errno = saved_errno;
!             return -1;
!           }
        }
      }
  
!   return chmod_or_fchmod (name, desc, mode);
  #else
  
  # if USE_ACL && defined ACL_NO_TRIVIAL





reply via email to

[Prev in Thread] Current Thread [Next in Thread]