[Top][All Lists]
[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