Cygwin: introduce fhandler_process_fd and add stat(2) handling

move special fd symlink code into own fhandler_process_fd class
to simplify further additions to /proc/PID/fd/DESCRIPTOR symlink
handling.

Add a method to handle stat(2) on such a proc fd symlink by handle.
This allows correct reply from stat(2) if the target file has been
deleted.  This eventually fixes `awk -f /dev/fd/3 3<<eof'.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2019-01-06 20:18:14 +01:00
parent ba12614f79
commit 7aca27b4fe
6 changed files with 189 additions and 164 deletions

View File

@ -288,6 +288,7 @@ DLL_OFILES:= \
fhandler_nodevice.o \
fhandler_proc.o \
fhandler_process.o \
fhandler_process_fd.o \
fhandler_procnet.o \
fhandler_procsys.o \
fhandler_procsysvipc.o \

View File

@ -552,9 +552,11 @@ fh_alloc (path_conv& pc)
fh = cnew (fhandler_registry);
break;
case FH_PROCESS:
case FH_PROCESSFD:
fh = cnew (fhandler_process);
break;
case FH_PROCESSFD:
fh = cnew (fhandler_process_fd);
break;
case FH_PROCNET:
fh = cnew (fhandler_procnet);
break;

View File

@ -2545,6 +2545,7 @@ class fhandler_registry: public fhandler_proc
class pinfo;
class fhandler_process: public fhandler_proc
{
protected:
pid_t pid;
virtual_ftype_t fd_type;
public:
@ -2554,8 +2555,6 @@ class fhandler_process: public fhandler_proc
int closedir (DIR *);
int __reg3 readdir (DIR *, dirent *);
int open (int flags, mode_t mode = 0);
virtual fhandler_base *fd_reopen (int);
int __reg2 link (const char *);
int __reg2 fstat (struct stat *buf);
bool fill_filebuf ();
@ -2577,6 +2576,34 @@ class fhandler_process: public fhandler_proc
}
};
class fhandler_process_fd : public fhandler_process
{
fhandler_base *fetch_fh (HANDLE &);
public:
fhandler_process_fd () : fhandler_process () {}
fhandler_process_fd (void *) {}
virtual fhandler_base *fd_reopen (int);
int __reg2 fstat (struct stat *buf);
virtual int __reg2 link (const char *);
void copyto (fhandler_base *x)
{
x->pc.free_strings ();
*reinterpret_cast<fhandler_process_fd *> (x) = *this;
x->reset (this);
}
fhandler_process_fd *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_process_fd));
fhandler_process_fd *fh = new (ptr) fhandler_process_fd (ptr);
copyto (fh);
return fh;
}
};
class fhandler_procnet: public fhandler_proc
{
pid_t pid;
@ -2638,6 +2665,7 @@ typedef union
char __pipe[sizeof (fhandler_pipe)];
char __proc[sizeof (fhandler_proc)];
char __process[sizeof (fhandler_process)];
char __process_fd[sizeof (fhandler_process_fd)];
char __procnet[sizeof (fhandler_procnet)];
char __procsys[sizeof (fhandler_procsys)];
char __procsysvipc[sizeof (fhandler_procsysvipc)];

View File

@ -321,166 +321,6 @@ out:
return res;
}
fhandler_base *
fhandler_process::fd_reopen (int flags)
{
const char *path;
char *e;
int fd;
HANDLE proc = NULL;
HANDLE hdl = NULL;
fhandler_base *fh = NULL;
path = get_name () + proc_len + 1;
pid = strtoul (path, &e, 10);
path = e + 4;
fd = strtoul (path, &e, 10);
if (e == path || *e != '\0')
{
set_errno (ENOENT);
return NULL;
}
if (pid == myself->pid)
{
cygheap_fdget cfd (fd);
if (cfd < 0)
return NULL;
fh = build_fh_pc (cfd->pc);
if (!fh)
goto err_out;
fh->set_io_handle (cfd->get_handle ());
}
else
{
size_t size;
path_conv pc;
pinfo p (pid);
if (!p)
{
set_errno (ENOENT);
return NULL;
}
if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId)))
{
__seterrno ();
return NULL;
}
void *buf = p->file_pathconv (fd, size);
if (size == 0)
{
set_errno (EPERM);
goto err_out;
}
hdl = pc.deserialize (buf);
if (!DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
0, FALSE, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
hdl = NULL;
goto err_out;
}
fh = build_fh_pc (pc);
if (!fh)
goto err_out;
fh->set_io_handle (hdl);
}
if (!fh->open_with_arch (flags, 0))
{
delete fh;
fh = NULL;
}
err_out:
if (hdl)
CloseHandle (hdl);
if (proc)
CloseHandle (proc);
return fh;
}
int
fhandler_process::link (const char *newpath)
{
const char *path;
int fd;
char *e;
path = get_name () + proc_len + 1;
pid = atoi (path);
while (*path != 0 && !isdirsep (*path))
path++;
if (*path == 0)
goto err_out;
virt_tab_t *entry;
entry = virt_tab_search (path + 1, true, process_tab, PROCESS_LINK_COUNT);
if (!entry || entry->fhandler != FH_PROCESSFD)
goto err_out;
if (path[3] != '/' || path[4] == '\0')
goto err_out;
fd = strtoul (path + 4, &e, 10);
if (fd < 0 || e == path + 4 || (*e != '/' && *e != '\0'))
goto err_out;
if (pid == myself->pid)
{
cygheap_fdget cfd (fd);
if (cfd < 0)
goto err_out;
return cfd->link (newpath);
}
else
{
HANDLE proc;
size_t size;
void *buf;
path_conv pc;
HANDLE hdl;
fhandler_base *fh = NULL;
int ret = -1;
pinfo p (pid);
if (!p)
{
set_errno (ENOENT);
return -1;
}
if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId)))
goto err_out;
buf = p->file_pathconv (fd, size);
if (size == 0)
{
set_errno (EPERM);
goto err_out_close_proc;
}
hdl = pc.deserialize (buf);
if (!DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
0, FALSE, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
goto err_out_close_proc;
}
fh = build_fh_pc (pc);
if (!fh)
goto err_out_close_dup;
fh->set_io_handle (hdl);
ret = fh->link (newpath);
delete fh;
err_out_close_dup:
CloseHandle (hdl);
err_out_close_proc:
CloseHandle (proc);
return ret;
}
err_out:
set_errno (EPERM);
return -1;
}
struct process_fd_t {
const char *path;
_pinfo *p;

View File

@ -0,0 +1,153 @@
/* fhandler_process_fd.cc: fhandler for /proc/<pid>/fd/<desc> operations
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
#include "fhandler.h"
#include "fhandler_virtual.h"
#include "pinfo.h"
#include "shared_info.h"
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
#include "cygtls.h"
#include "mount.h"
#include "tls_pbuf.h"
#include <sys/sysmacros.h>
#include <sys/param.h>
#include <ctype.h>
fhandler_base *
fhandler_process_fd::fetch_fh (HANDLE &out_hdl)
{
const char *path;
char *e;
int fd;
HANDLE proc;
HANDLE hdl = NULL;
path_conv pc;
path = get_name () + proc_len + 1;
pid = strtoul (path, &e, 10);
path = e + 4;
fd = strtoul (path, &e, 10);
out_hdl = NULL;
if (pid == myself->pid)
{
cygheap_fdget cfd (fd, true);
if (cfd < 0)
return NULL;
proc = GetCurrentProcess ();
pc << cfd->pc;
hdl = cfd->get_handle ();
}
else
{
pinfo p (pid);
if (!p)
{
set_errno (ENOENT);
return NULL;
}
proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId);
if (!proc)
{
__seterrno ();
return NULL;
}
size_t size;
void *buf = p->file_pathconv (fd, size);
if (size == 0)
{
set_errno (EPERM);
CloseHandle (proc);
return NULL;
}
hdl = pc.deserialize (buf);
}
BOOL ret = DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
0, FALSE, DUPLICATE_SAME_ACCESS);
if (proc != GetCurrentProcess ())
CloseHandle (proc);
if (!ret)
{
__seterrno ();
CloseHandle (hdl);
return NULL;
}
fhandler_base *fh = build_fh_pc (pc);
if (!fh)
{
CloseHandle (hdl);
return NULL;
}
out_hdl = hdl;
return fh;
}
fhandler_base *
fhandler_process_fd::fd_reopen (int flags)
{
fhandler_base *fh;
HANDLE hdl;
fh = fetch_fh (hdl);
if (!fh)
return NULL;
fh->set_io_handle (hdl);
int ret = fh->open_with_arch (flags, 0);
CloseHandle (hdl);
if (!ret)
{
delete fh;
fh = NULL;
}
return fh;
}
int __reg2
fhandler_process_fd::fstat (struct stat *statbuf)
{
if (!pc.follow_fd_symlink ())
return fhandler_process::fstat (statbuf);
fhandler_base *fh;
HANDLE hdl;
fh = fetch_fh (hdl);
if (!fh)
return -1;
fh->set_io_handle (hdl);
int ret = fh->fstat (statbuf);
CloseHandle (hdl);
delete fh;
return ret;
}
int
fhandler_process_fd::link (const char *newpath)
{
fhandler_base *fh;
HANDLE hdl;
fh = fetch_fh (hdl);
if (!fh)
return -1;
fh->set_io_handle (hdl);
int ret = fh->link (newpath);
CloseHandle (hdl);
delete fh;
return ret;
}

View File

@ -2005,7 +2005,8 @@ extern "C" int
stat64 (const char *__restrict name, struct stat *__restrict buf)
{
syscall_printf ("entering");
path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE,
path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE
| PC_SYM_NOFOLLOW_PROCFD,
stat_suffixes);
return stat_worker (pc, buf);
}