Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/fhandler/process_fd.cc')
-rw-r--r--winsup/cygwin/fhandler/process_fd.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler/process_fd.cc b/winsup/cygwin/fhandler/process_fd.cc
new file mode 100644
index 000000000..d81495103
--- /dev/null
+++ b/winsup/cygwin/fhandler/process_fd.cc
@@ -0,0 +1,163 @@
+/* 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;
+}