summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/syscalls.cc
diff options
context:
space:
mode:
authorKen Brown <kbrown@cornell.edu>2017-08-17 09:12:15 -0400
committerCorinna Vinschen <corinna@vinschen.de>2017-08-19 18:06:49 +0200
commitf665b1cef30f9032877081ac63ea94910825be6a (patch)
tree4b2a63cc2ac9b59434af3907a6a4f2bc49866197 /winsup/cygwin/syscalls.cc
parentc496cbb6bdbe7d5a81aff83fbaafa2c92336a544 (diff)
downloadcygnal-f665b1cef30f9032877081ac63ea94910825be6a.tar.gz
cygnal-f665b1cef30f9032877081ac63ea94910825be6a.tar.bz2
cygnal-f665b1cef30f9032877081ac63ea94910825be6a.zip
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.
Diffstat (limited to 'winsup/cygwin/syscalls.cc')
-rw-r--r--winsup/cygwin/syscalls.cc48
1 files changed, 42 insertions, 6 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 885931632..61872fe58 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -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);
@@ -2579,6 +2602,12 @@ rename (const char *oldpath, const char *newpath)
}
extern "C" int
+rename (const char *oldpath, const char *newpath)
+{
+ return rename2 (oldpath, newpath, 0);
+}
+
+extern "C" int
system (const char *cmdstring)
{
pthread_testcancel ();
@@ -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,7 +4760,7 @@ 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
@@ -4739,6 +4768,13 @@ renameat (int olddirfd, const char *oldpathname,
}
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 *),
int (*compar) (const struct dirent **, const struct dirent **))