From: Ken Brown <kbrown@cornell.edu>
To: cygwin-developers@cygwin.com
Subject: Re: fstat and similar methods in fhandler_socket_local and fhandler_socket_unix
Date: Thu, 25 Feb 2021 08:18:06 -0500 [thread overview]
Message-ID: <0be341b4-371e-2941-4407-93bef6ff3871@cornell.edu> (raw)
In-Reply-To: <76be1cd8-0b9a-3689-0b9e-cea689178a16@cornell.edu>
On 2/24/2021 12:27 PM, Ken Brown via Cygwin-developers wrote:
> On 2/24/2021 12:06 PM, Corinna Vinschen via Cygwin-developers wrote:
>> On Feb 24 10:32, Ken Brown via Cygwin-developers wrote:
>>> On 2/24/2021 4:06 AM, Corinna Vinschen via Cygwin-developers wrote:
>>>> On Feb 22 15:01, Ken Brown via Cygwin-developers wrote:
>>>>> OK, I've got patches ready to go for fstat, fstatvfs, fchmod, fchown, facl,
>>>>> and link. I have to test them, and then I'll send them to cygwin-patches.
>>>>> In the case of link, I think the only way an fhandler_socket's link method
>>>>> can be called is through link(2) being called on a socket file. So the
>>>>> following should do the job:
>>>>>
>>>>> diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
>>>>> index 21e1df172..f4aa12956 100644
>>>>> --- a/winsup/cygwin/fhandler.h
>>>>> +++ b/winsup/cygwin/fhandler.h
>>>>> @@ -611,7 +611,6 @@ class fhandler_socket: public fhandler_base
>>>>> int __reg1 fchmod (mode_t newmode);
>>>>> int __reg2 fchown (uid_t newuid, gid_t newgid);
>>>>> int __reg3 facl (int, int, struct acl *);
>>>>> - int __reg2 link (const char *);
>>>>> off_t lseek (off_t, int)
>>>>> {
>>>>> set_errno (ESPIPE);
>>>>> diff --git a/winsup/cygwin/fhandler_socket.cc
>>>>> b/winsup/cygwin/fhandler_socket.cc
>>>>> index f22412650..08870cc6b 100644
>>>>> --- a/winsup/cygwin/fhandler_socket.cc
>>>>> +++ b/winsup/cygwin/fhandler_socket.cc
>>>>> @@ -357,9 +357,3 @@ fhandler_socket::facl (int cmd, int nentries, aclent_t
>>>>> *aclbufp)
>>>>> set_errno (EOPNOTSUPP);
>>>>> return -1;
>>>>> }
>>>>> -
>>>>> -int
>>>>> -fhandler_socket::link (const char *newpath)
>>>>> -{
>>>>> - return fhandler_base::link (newpath);
>>>>> -}
>>>>
>>>> Hmm. What about linkat (AT_EMPTY_PATH, socket, ...)?
While working on this, I discovered that linkat(AT_EMPTY_PATH) doesn't currently
work on socket files opened with O_PATH. I started debugging this (not finished
yet), and it occurred to me that the implementation of linkat(AT_EMPTY_PATH)
could be simplified like this:
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -4962,6 +4962,8 @@ linkat (int olddirfd, const char *oldpathname,
int flags)
{
tmp_pathbuf tp;
+ fhandler_base *fh = NULL;
+
__try
{
if (flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH))
@@ -4970,21 +4972,19 @@ linkat (int olddirfd, const char *oldpathname,
__leave;
}
char *oldpath = tp.c_get ();
- /* AT_EMPTY_PATH with an empty oldpathname is equivalent to
-
- linkat(AT_FDCWD, "/proc/self/fd/<olddirfd>", newdirfd,
- newname, AT_SYMLINK_FOLLOW);
-
- Convert the request accordingly. */
if ((flags & AT_EMPTY_PATH) && oldpathname && oldpathname[0] == '\0')
{
+ /* Operate directly on olddirfd. */
if (olddirfd == AT_FDCWD)
{
set_errno (EPERM);
__leave;
}
- __small_sprintf (oldpath, "/proc/%d/fd/%d", myself->pid, olddirfd);
- flags = AT_SYMLINK_FOLLOW;
+ cygheap_fdget cfd (olddirfd);
+ if (cfd < 0)
+ __leave;
+ fh = cfd;
+ flags = 0;
}
else if (gen_full_path_at (oldpath, olddirfd, oldpathname))
__leave;
@@ -5003,6 +5003,8 @@ linkat (int olddirfd, const char *oldpathname,
}
strcpy (oldpath, old_name.get_posix ());
}
+ if (fh)
+ return fh->link (newpath);
return link (oldpath, newpath);
}
__except (EFAULT) {}
This seems to work fine on regular files and on socket files opened with O_PATH,
after I tweak fhandler_socket_local::link (see below). I haven't tested other
file types yet.
$ cat linkat_test.c
#define _GNU_SOURCE
#include <sys/types.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define FILE "/tmp/myfile"
#define NEW_FILE "/tmp/mynewfile"
#define SOCK_PATH "/tmp/mysocket"
#define NEW_SOCK_PATH "/tmp/mynewsocket"
int
main ()
{
struct sockaddr_un addr;
int fd;
/* Regular file. */
if (unlink (FILE) < 0 && errno != ENOENT)
{
perror ("unlink");
exit (1);
}
if (unlink (NEW_FILE) < 0 && errno != ENOENT)
{
perror ("unlink");
exit (1);
}
fd = open (FILE, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
{
perror ("open");
exit (1);
}
printf ("Testing linkat (AT_EMPTY_PATH) on a regular file...\n");
if (linkat (fd, "", AT_FDCWD, NEW_FILE, AT_EMPTY_PATH) < 0)
perror ("linkat");
else
printf ("success\n\n");
if (close (fd) < 0)
{
perror ("close");
exit (1);
}
/* Socket file. */
if (unlink (SOCK_PATH) < 0 && errno != ENOENT)
{
perror ("unlink");
exit (1);
}
if (unlink (NEW_SOCK_PATH) < 0 && errno != ENOENT)
{
perror ("unlink");
exit (1);
}
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
{
perror ("socket");
exit (1);
}
memset (&addr, 0, sizeof (struct sockaddr_un));
addr.sun_family = AF_UNIX;
strcpy (addr.sun_path, SOCK_PATH);
if (bind (fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0)
{
perror ("bind");
exit (1);
}
if (close (fd) < 0)
{
perror ("close");
exit (1);
}
fd = open (SOCK_PATH, O_PATH);
if (fd < 0)
{
perror ("open");
exit (1);
}
printf ("Testing linkat (AT_EMPTY_PATH) on a socket file...\n");
if (linkat (fd, "", AT_FDCWD, NEW_SOCK_PATH, AT_EMPTY_PATH) < 0)
perror ("linkat");
else
printf ("success\n");
if (close (fd) < 0)
{
perror ("close");
exit (1);
}
}
$ gcc -g -O0 -o linkat_test linkat_test.c
$ ./linkat_test.exe
Testing linkat (AT_EMPTY_PATH) on a regular file...
success
Testing linkat (AT_EMPTY_PATH) on a socket file...
success
$ ls -l /tmp/my*
-rw------- 2 kbrown None 0 2021-02-25 07:59 /tmp/myfile
-rw------- 2 kbrown None 0 2021-02-25 07:59 /tmp/mynewfile
srw-r--r-- 2 kbrown None 0 2021-02-25 07:59 /tmp/mynewsocket=
srw-r--r-- 2 kbrown None 0 2021-02-25 07:59 /tmp/mysocket=
And here's the tweak to fhandler_socket_local::link:
--- a/winsup/cygwin/fhandler_socket_local.cc
+++ b/winsup/cygwin/fhandler_socket_local.cc
@@ -749,9 +749,14 @@ fhandler_socket_local::facl (int cmd, int nentries,
aclent_t *aclbufp)
int
fhandler_socket_local::link (const char *newpath)
{
- if (get_sun_path () && get_sun_path ()[0] == '\0')
+ if (!dev ().isfs ())
+ /* linkat w/ AT_EMPTY_PATH called on a socket not opened w/ O_PATH. */
return fhandler_socket_wsock::link (newpath);
+ /* link on a socket file or linkat w/ AT_EMPTY_PATH called on a
+ socket opened w/ O_PATH. */
fhandler_disk_file fh (pc);
+ if (get_flags () & O_PATH)
+ fh.set_handle (get_handle ());
return fh.link (newpath);
}
I'll put all this together in a patchset, along with the tweaks to fstat, etc.,
but first I wanted to get your reaction to the proposed simplification of
linkat(AT_EMPTY_PATH).
Thanks.
Ken
next prev parent reply other threads:[~2021-02-25 13:18 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-20 23:32 Ken Brown
2021-02-20 23:51 ` Ken Brown
2021-02-21 18:04 ` Ken Brown
2021-02-22 9:44 ` Corinna Vinschen
2021-02-22 20:01 ` Ken Brown
2021-02-24 9:06 ` Corinna Vinschen
2021-02-24 15:32 ` Ken Brown
2021-02-24 17:06 ` Corinna Vinschen
2021-02-24 17:27 ` Ken Brown
2021-02-25 13:18 ` Ken Brown [this message]
2021-02-25 17:03 ` Corinna Vinschen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0be341b4-371e-2941-4407-93bef6ff3871@cornell.edu \
--to=kbrown@cornell.edu \
--cc=cygwin-developers@cygwin.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).