/* fhandler_process_fd.cc: fhandler for /proc//fd/ 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; }