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