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_nodevice.o \
|
||||||
fhandler_proc.o \
|
fhandler_proc.o \
|
||||||
fhandler_process.o \
|
fhandler_process.o \
|
||||||
|
fhandler_process_fd.o \
|
||||||
fhandler_procnet.o \
|
fhandler_procnet.o \
|
||||||
fhandler_procsys.o \
|
fhandler_procsys.o \
|
||||||
fhandler_procsysvipc.o \
|
fhandler_procsysvipc.o \
|
||||||
|
|
|
@ -552,9 +552,11 @@ fh_alloc (path_conv& pc)
|
||||||
fh = cnew (fhandler_registry);
|
fh = cnew (fhandler_registry);
|
||||||
break;
|
break;
|
||||||
case FH_PROCESS:
|
case FH_PROCESS:
|
||||||
case FH_PROCESSFD:
|
|
||||||
fh = cnew (fhandler_process);
|
fh = cnew (fhandler_process);
|
||||||
break;
|
break;
|
||||||
|
case FH_PROCESSFD:
|
||||||
|
fh = cnew (fhandler_process_fd);
|
||||||
|
break;
|
||||||
case FH_PROCNET:
|
case FH_PROCNET:
|
||||||
fh = cnew (fhandler_procnet);
|
fh = cnew (fhandler_procnet);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2545,6 +2545,7 @@ class fhandler_registry: public fhandler_proc
|
||||||
class pinfo;
|
class pinfo;
|
||||||
class fhandler_process: public fhandler_proc
|
class fhandler_process: public fhandler_proc
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
virtual_ftype_t fd_type;
|
virtual_ftype_t fd_type;
|
||||||
public:
|
public:
|
||||||
|
@ -2554,8 +2555,6 @@ class fhandler_process: public fhandler_proc
|
||||||
int closedir (DIR *);
|
int closedir (DIR *);
|
||||||
int __reg3 readdir (DIR *, dirent *);
|
int __reg3 readdir (DIR *, dirent *);
|
||||||
int open (int flags, mode_t mode = 0);
|
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);
|
int __reg2 fstat (struct stat *buf);
|
||||||
bool fill_filebuf ();
|
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
|
class fhandler_procnet: public fhandler_proc
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
@ -2638,6 +2665,7 @@ typedef union
|
||||||
char __pipe[sizeof (fhandler_pipe)];
|
char __pipe[sizeof (fhandler_pipe)];
|
||||||
char __proc[sizeof (fhandler_proc)];
|
char __proc[sizeof (fhandler_proc)];
|
||||||
char __process[sizeof (fhandler_process)];
|
char __process[sizeof (fhandler_process)];
|
||||||
|
char __process_fd[sizeof (fhandler_process_fd)];
|
||||||
char __procnet[sizeof (fhandler_procnet)];
|
char __procnet[sizeof (fhandler_procnet)];
|
||||||
char __procsys[sizeof (fhandler_procsys)];
|
char __procsys[sizeof (fhandler_procsys)];
|
||||||
char __procsysvipc[sizeof (fhandler_procsysvipc)];
|
char __procsysvipc[sizeof (fhandler_procsysvipc)];
|
||||||
|
|
|
@ -321,166 +321,6 @@ out:
|
||||||
return res;
|
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 {
|
struct process_fd_t {
|
||||||
const char *path;
|
const char *path;
|
||||||
_pinfo *p;
|
_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)
|
stat64 (const char *__restrict name, struct stat *__restrict buf)
|
||||||
{
|
{
|
||||||
syscall_printf ("entering");
|
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);
|
stat_suffixes);
|
||||||
return stat_worker (pc, buf);
|
return stat_worker (pc, buf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue