Cygwin: Move O_TMPFILE to bin and allow linkat by handle
Along the same lines as the previous patch: By reopening an O_TMPFILE by handle, we can now move the file to the bin at open time and thus free'ing up the parent dir and *still* open the file as /proc/PID/fd/DESCRIPTOR by linkat(2).
This commit is contained in:
		| @@ -2555,6 +2555,7 @@ class fhandler_process: public fhandler_proc | ||||
|   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 (); | ||||
|  | ||||
|   | ||||
| @@ -399,6 +399,88 @@ err_out: | ||||
|   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; | ||||
|   | ||||
| @@ -1484,6 +1484,10 @@ open (const char *unix_path, int flags, ...) | ||||
|       else if ((fh->is_fs_special () && fh->device_access_denied (flags)) | ||||
| 	       || !fh->open_with_arch (flags, mode & 07777)) | ||||
| 	__leave;		/* errno already set */ | ||||
|       /* Move O_TMPFILEs to the bin to avoid blocking the parent dir. */ | ||||
|       if ((flags & O_TMPFILE) && !fh->pc.isremote ()) | ||||
| 	try_to_bin (fh->pc, fh->get_handle (), DELETE, | ||||
| 		    FILE_OPEN_FOR_BACKUP_INTENT); | ||||
|       fd = fh; | ||||
|       if (fd <= 2) | ||||
| 	set_std_handle (fd); | ||||
| @@ -4791,7 +4795,9 @@ linkat (int olddirfd, const char *oldpathname, | ||||
| 	__leave; | ||||
|       if (flags & AT_SYMLINK_FOLLOW) | ||||
| 	{ | ||||
| 	  path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); | ||||
| 	  path_conv old_name (oldpath, | ||||
| 			      PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_PROCFD | PC_POSIX, | ||||
| 			      stat_suffixes); | ||||
| 	  if (old_name.error) | ||||
| 	    { | ||||
| 	      set_errno (old_name.error); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user