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:
parent
ba12614f79
commit
7aca27b4fe
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue