|
|
|
@ -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 *), |
|
|
|
|