newlib-cygwin/winsup/cygwin/fhandler_process_fd.cc

164 lines
3.2 KiB
C++

/* 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 "path.h"
#include "fhandler.h"
#include "fhandler_virtual.h"
#include "pinfo.h"
#include "dtable.h"
#include "cygheap.h"
#include "tls_pbuf.h"
fhandler_base *
fhandler_process_fd::fetch_fh (HANDLE &out_hdl, uint32_t flags)
{
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;
if ((flags & FFH_LINKAT)
&& (cfd->get_flags () & (O_TMPFILE | O_EXCL)) == (O_TMPFILE | O_EXCL))
{
set_errno (ENOENT);
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, flags, size);
if (size == 0)
{
set_errno (ENOENT);
CloseHandle (proc);
return NULL;
}
hdl = pc.deserialize (buf);
}
if (hdl == NULL)
{
if (proc != GetCurrentProcess ())
CloseHandle (proc);
set_errno (EACCES);
return NULL;
}
BOOL ret = DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl,
0, FALSE, DUPLICATE_SAME_ACCESS);
if (proc != GetCurrentProcess ())
CloseHandle (proc);
if (!ret)
{
__seterrno ();
CloseHandle (hdl);
return NULL;
}
/* relative path? This happens for special types like pipes and sockets. */
if (*pc.get_posix () != '/')
{
tmp_pathbuf tp;
char *fullpath = tp.c_get ();
stpcpy (stpncpy (fullpath, get_name (), path - get_name ()),
pc.get_posix ());
pc.set_posix (fullpath);
}
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, mode_t mode)
{
fhandler_base *fh;
HANDLE hdl;
fh = fetch_fh (hdl, 0);
if (!fh)
return NULL;
fh->set_handle (hdl);
int ret = fh->open_with_arch (flags, mode);
CloseHandle (hdl);
if (!ret)
{
delete fh;
fh = NULL;
}
return fh;
}
int
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, 0);
if (!fh)
return -1;
fh->set_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, FFH_LINKAT);
if (!fh)
return -1;
fh->set_handle (hdl);
int ret = fh->link (newpath);
CloseHandle (hdl);
delete fh;
return ret;
}