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