Hi, cp has some issues with O_NOFOLLOW meaning O_NOTRANS (per __hurd_file_name_lookup). One of them is when opening pipes with O_NOFOLLOW (or when opening them with O_NOTRANS, which is the problem here). Then the permissions are checked in libdiskfs (if the pipe is in an ext2fs partition for example), which has the following in libdiskfs/dir-lookup.c:
if (((type == S_IFSOCK || type == S_IFBLK || type == S_IFCHR || type == S_IFIFO) && (flags & (O_READ|O_WRITE|O_EXEC))) || (type == S_IFLNK && (flags & (O_WRITE|O_EXEC)))) error = EACCES; So opening a named pipe with open(pipe, O_RDONLY | O_NOTRANS, 0) will cause EACCES. I wonder what is the reason for not allowing access to those kind of files if they are opened with O_READ, O_WRITE or O_EXEC. Why can't they be allowed, as long as the opener has the appropriate permissions (which will be checked later)? The attached eacces.c program reproduces this issue. The other problem is that an stat on a named pipe like fd = open (pipe, O_RDONLY | O_NOFOLLOW, 0); fstat (fd, &sb); Doesn't match this: lstat (pipe, &sb); In particular, sb.st_dev will be different. The problem is that lstat uses O_NOLINK internally, and since the named pipe is not a symlink, it will get the underlying node, and the io_stat call will be handled by the fifo translator, which will return its PID in st_dev. However the open call has O_NOFOLLOW, which implies O_NOTRANS and thus it doesn't get the underlying node, returning the correct st_dev. Would it be possible to make these kind of translators return the device id of its parent? The attached stat.c testcase reproduces this issue (you can remove the O_NOFOLLOW flag to see the devices matching, but being the PID of the fifo translator). Regards, Emilio
#define _GNU_SOURCE #include <hurd.h> #include <error.h> #include <fcntl.h> int main (int argc, char **argv) { file_t file; if (argc < 2) error (1, 0, "Usage: %s <file>", argv[0]); file = file_name_lookup (argv[1], O_RDONLY | O_NOFOLLOW, 0); if (file == MACH_PORT_NULL) error (1, errno, "error when opening %s", argv[1]); return 0; }
#define _GNU_SOURCE #include <error.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> # define SAME_INODE(Stat_buf_1, Stat_buf_2) \ ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) int main (int argc, char **argv) { int fd; struct stat st1, st2; if (argc != 2) error (1, 0, "Usage: %s <file>", argv[0]); if ((fd = open (argv[1], O_RDONLY | O_NOFOLLOW, 0)) == -1) error (1, errno, "error when opening %s", argv[1]); if (fstat (fd, &st1) == -1) error (1, errno, "error when stating %s", argv[1]); if (lstat (argv[1], &st2) == -1) error (1, errno, "error when stating %s", argv[1]); printf ("devices: %d %d, %d %d\n", st1.st_dev, st2.st_dev); if (SAME_INODE(st1, st2)) printf ("same inode!\n"); else printf ("different inode!\n"); return 0; }