fstat and similar methods in fhandler_socket_local and fhandler_socket_unix
Ken Brown
kbrown@cornell.edu
Sat Feb 20 23:51:24 GMT 2021
On 2/20/2021 6:32 PM, Ken Brown via Cygwin-developers wrote:
> fhandler_socket_local::fstat and many similar methods seem to assume that the
> fhandler is based on a socket *file*. When this is not the case, they end up
> using handles inappropriately. Consider the following test case, for example.
>
> $ cat socket_stat.c
> #include <time.h>
> #include <sys/socket.h>
> #include <sys/un.h>
> #include <sys/stat.h>
> #include <errno.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
>
> void print_stat (struct stat);
>
> int
> main ()
> {
> struct stat st;
> int fd;
>
> fd = socket (AF_UNIX, SOCK_STREAM, 0);
> if (fd == -1)
> {
> perror ("socket");
> exit (1);
> }
> if (fstat (fd, &st) < 0)
> {
> perror ("fstat");
> exit (1);
> }
> print_stat (st);
> }
>
> /* https://man7.org/linux/man-pages/man2/lstat.2.html */
> void
> print_stat (struct stat st)
> {
> printf("File type: ");
>
> switch (st.st_mode & S_IFMT) {
> case S_IFBLK: printf("block device\n"); break;
> case S_IFCHR: printf("character device\n"); break;
> case S_IFDIR: printf("directory\n"); break;
> case S_IFIFO: printf("FIFO/pipe\n"); break;
> case S_IFLNK: printf("symlink\n"); break;
> case S_IFREG: printf("regular file\n"); break;
> case S_IFSOCK: printf("socket\n"); break;
> default: printf("unknown?\n"); break;
> }
>
> printf("I-node number: %ld\n", (long) st.st_ino);
> printf("dev: %lu\n", st.st_dev);
> printf("rdev: %lu\n", st.st_rdev);
> printf("Mode: %lo (octal)\n",
> (unsigned long) st.st_mode);
>
> printf("Link count: %ld\n", (long) st.st_nlink);
> printf("Ownership: UID=%ld GID=%ld\n",
> (long) st.st_uid, (long) st.st_gid);
>
> printf("Preferred I/O block size: %ld bytes\n",
> (long) st.st_blksize);
> printf("File size: %lld bytes\n",
> (long long) st.st_size);
> printf("Blocks allocated: %lld\n",
> (long long) st.st_blocks);
>
> printf("Last status change: %s", ctime(&st.st_ctime));
> printf("Last file access: %s", ctime(&st.st_atime));
> printf("Last file modification: %s", ctime(&st.st_mtime));
> printf("\n");
> }
>
> $ gcc -g -O0 -o socket_stat socket_stat.c
>
> $ ./socket_stat.exe
> File type: socket
> I-node number: 4
> dev: 1966200
> rdev: 1966200
> Mode: 140644 (octal)
> Link count: 0
> Ownership: UID=197609 GID=197121
> Preferred I/O block size: 65536 bytes
> File size: 0 bytes
> Blocks allocated: 0
> Last status change: Wed Dec 31 19:00:00 1969
> Last file access: Wed Dec 31 19:00:00 1969
> Last file modification: Wed Dec 31 19:00:00 1969
>
> On Linux the output is:
>
> File type: socket
> I-node number: 117
> dev: 0
> rdev: 0
> Mode: 140777 (octal)
> Link count: 1
> Ownership: UID=1000 GID=1000
> Preferred I/O block size: 512 bytes
> File size: 0 bytes
> Blocks allocated: 0
> Last status change: Sat Feb 20 18:13:50 2021
> Last file access: Sat Feb 20 18:13:50 2021
> Last file modification: Sat Feb 20 18:13:50 2021
>
> I haven't been able to find any documentation about what fstat(2) should do on a
> socket descriptor, so maybe the difference between Cygwin and Linux is
> unimportant. But the code path followed on Cygwin definitely seems wrong.
> fhandler_socket_local::fstat calls fstat_fs which ends up using the io_handle as
> though it were a file handle. It seems to me that fstat_fs should only be
> called if we have a path_conv handle (which is the case if the fstat call
> resulted from a stat call) or if the socket descriptor came from open with
> O_PATH set.
>
> Similar remarks apply to fstatfvs, fchmod,.... In some of these cases, like
> fchmod, POSIX explicitly states that the behavior is undefined, so maybe we
> should just fail when there's no underlying socket file.
Maybe the answer in all these cases is just to revert to the fhandler_socket
methods when our fhandler_socket_local is not based on a socket file.
Ken
More information about the Cygwin-developers
mailing list