cygwin: Implement renameat2
Define the RENAME_NOREPLACE flag in <cygwin/fs.h> as defined on Linux in <linux/fs.h>. The other RENAME_* flags defined on Linux are not supported.
This commit is contained in:
		
				
					committed by
					
						 Corinna Vinschen
						Corinna Vinschen
					
				
			
			
				
	
			
			
			
						parent
						
							c496cbb6bd
						
					
				
				
					commit
					f665b1cef3
				
			| @@ -384,6 +384,9 @@ int	_EXFUN(vdprintf, (int, const char *__restrict, __VALIST) | ||||
| #endif | ||||
| #if __ATFILE_VISIBLE | ||||
| int	_EXFUN(renameat, (int, const char *, int, const char *)); | ||||
| # ifdef __CYGWIN__ | ||||
| int	_EXFUN(renameat2, (int, const char *, int, const char *, unsigned int)); | ||||
| # endif | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -1168,6 +1168,7 @@ remquof NOSIGFE | ||||
| remquol NOSIGFE | ||||
| rename SIGFE | ||||
| renameat SIGFE | ||||
| renameat2 SIGFE | ||||
| res_close = __res_close SIGFE | ||||
| res_init = __res_init SIGFE | ||||
| res_mkquery = __res_mkquery SIGFE | ||||
|   | ||||
| @@ -19,4 +19,10 @@ details. */ | ||||
| #define BLKPBSZGET   0x0000127b | ||||
| #define BLKGETSIZE64 0x00041268 | ||||
|  | ||||
| /* Flags for renameat2, from /usr/include/linux/fs.h.  For now we | ||||
|    support only RENAME_NOREPLACE. */ | ||||
| #define RENAME_NOREPLACE (1 << 0) | ||||
| /* #define RENAME_EXCHANGE  (1 << 1) */ | ||||
| /* #define RENAME_WHITEOUT  (1 << 2) */ | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -481,12 +481,13 @@ details. */ | ||||
|   314: Export explicit_bzero. | ||||
|   315: Export pthread_mutex_timedlock. | ||||
|   316: Export pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock. | ||||
|   317: Export renameat2. | ||||
|  | ||||
|   Note that we forgot to bump the api for ualarm, strtoll, strtoull, | ||||
|   sigaltstack, sethostname. */ | ||||
|  | ||||
| #define CYGWIN_VERSION_API_MAJOR 0 | ||||
| #define CYGWIN_VERSION_API_MINOR 316 | ||||
| #define CYGWIN_VERSION_API_MINOR 317 | ||||
|  | ||||
| /* There is also a compatibity version number associated with the shared memory | ||||
|    regions.  It is incremented when incompatible changes are made to the shared | ||||
|   | ||||
| @@ -60,6 +60,7 @@ details. */ | ||||
| #include "tls_pbuf.h" | ||||
| #include "sync.h" | ||||
| #include "child_info.h" | ||||
| #include <cygwin/fs.h>  /* needed for RENAME_NOREPLACE */ | ||||
|  | ||||
| #undef _close | ||||
| #undef _lseek | ||||
| @@ -2048,14 +2049,19 @@ nt_path_has_executable_suffix (PUNICODE_STRING upath) | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| extern "C" int | ||||
| rename (const char *oldpath, const char *newpath) | ||||
| /* If newpath names an existing file and the RENAME_NOREPLACE flag is | ||||
|    specified, fail with EEXIST.  Exception: Don't fail if the purpose | ||||
|    of the rename is just to change the case of oldpath on a | ||||
|    case-insensitive file system. */ | ||||
| static int | ||||
| rename2 (const char *oldpath, const char *newpath, unsigned int flags) | ||||
| { | ||||
|   tmp_pathbuf tp; | ||||
|   int res = -1; | ||||
|   path_conv oldpc, newpc, new2pc, *dstpc, *removepc = NULL; | ||||
|   bool old_dir_requested = false, new_dir_requested = false; | ||||
|   bool old_explicit_suffix = false, new_explicit_suffix = false; | ||||
|   bool noreplace = flags & RENAME_NOREPLACE; | ||||
|   size_t olen, nlen; | ||||
|   bool equal_path; | ||||
|   NTSTATUS status = STATUS_SUCCESS; | ||||
| @@ -2068,6 +2074,12 @@ rename (const char *oldpath, const char *newpath) | ||||
|  | ||||
|   __try | ||||
|     { | ||||
|       if (flags & ~RENAME_NOREPLACE) | ||||
| 	/* RENAME_NOREPLACE is the only flag currently supported. */ | ||||
| 	{ | ||||
| 	  set_errno (EINVAL); | ||||
| 	  __leave; | ||||
| 	} | ||||
|       if (!*oldpath || !*newpath) | ||||
| 	{ | ||||
| 	  /* Reject rename("","x"), rename("x","").  */ | ||||
| @@ -2337,6 +2349,13 @@ rename (const char *oldpath, const char *newpath) | ||||
| 	  __leave; | ||||
| 	} | ||||
|  | ||||
|       /* Should we replace an existing file? */ | ||||
|       if ((removepc || dstpc->exists ()) && noreplace) | ||||
| 	{ | ||||
| 	  set_errno (EEXIST); | ||||
| 	  __leave; | ||||
| 	} | ||||
|  | ||||
|       /* Opening the file must be part of the transaction.  It's not sufficient | ||||
| 	 to call only NtSetInformationFile under the transaction.  Therefore we | ||||
| 	 have to start the transaction here, if necessary. */ | ||||
| @@ -2491,11 +2510,15 @@ rename (const char *oldpath, const char *newpath) | ||||
| 	  __leave; | ||||
| 	} | ||||
|       pfri = (PFILE_RENAME_INFORMATION) tp.w_get (); | ||||
|       pfri->ReplaceIfExists = TRUE; | ||||
|       pfri->ReplaceIfExists = !noreplace; | ||||
|       pfri->RootDirectory = NULL; | ||||
|       pfri->FileNameLength = dstpc->get_nt_native_path ()->Length; | ||||
|       memcpy (&pfri->FileName,  dstpc->get_nt_native_path ()->Buffer, | ||||
| 	      pfri->FileNameLength); | ||||
|       /* If dstpc points to an existing file and RENAME_NOREPLACE has | ||||
| 	 been specified, then we should get NT error | ||||
| 	 STATUS_OBJECT_NAME_COLLISION ==> Win32 error | ||||
| 	 ERROR_ALREADY_EXISTS ==> Cygwin error EEXIST. */ | ||||
|       status = NtSetInformationFile (fh, &io, pfri, | ||||
| 				     sizeof *pfri + pfri->FileNameLength, | ||||
| 				     FileRenameInformation); | ||||
| @@ -2578,6 +2601,12 @@ rename (const char *oldpath, const char *newpath) | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| extern "C" int | ||||
| rename (const char *oldpath, const char *newpath) | ||||
| { | ||||
|   return rename2 (oldpath, newpath, 0); | ||||
| } | ||||
|  | ||||
| extern "C" int | ||||
| system (const char *cmdstring) | ||||
| { | ||||
| @@ -4719,8 +4748,8 @@ readlinkat (int dirfd, const char *__restrict pathname, char *__restrict buf, | ||||
| } | ||||
|  | ||||
| extern "C" int | ||||
| renameat (int olddirfd, const char *oldpathname, | ||||
| 	  int newdirfd, const char *newpathname) | ||||
| renameat2 (int olddirfd, const char *oldpathname, | ||||
| 	   int newdirfd, const char *newpathname, unsigned int flags) | ||||
| { | ||||
|   tmp_pathbuf tp; | ||||
|   __try | ||||
| @@ -4731,13 +4760,20 @@ renameat (int olddirfd, const char *oldpathname, | ||||
|       char *newpath = tp.c_get (); | ||||
|       if (gen_full_path_at (newpath, newdirfd, newpathname)) | ||||
| 	__leave; | ||||
|       return rename (oldpath, newpath); | ||||
|       return rename2 (oldpath, newpath, flags); | ||||
|     } | ||||
|   __except (EFAULT) {} | ||||
|   __endtry | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| extern "C" int | ||||
| renameat (int olddirfd, const char *oldpathname, | ||||
| 	  int newdirfd, const char *newpathname) | ||||
| { | ||||
|   return renameat2 (olddirfd, oldpathname, newdirfd, newpathname, 0); | ||||
| } | ||||
|  | ||||
| extern "C" int | ||||
| scandirat (int dirfd, const char *pathname, struct dirent ***namelist, | ||||
| 	   int (*select) (const struct dirent *), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user