Make w32_rename() Atomic For Files (#438)

This commit is contained in:
Bryan Berns 2020-04-02 13:17:27 -04:00 committed by GitHub
parent 901f123915
commit 106db2baac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -41,9 +41,9 @@
#include <LM.h> #include <LM.h>
#include <Sddl.h> #include <Sddl.h>
#include <Aclapi.h> #include <Aclapi.h>
#include <Ntsecapi.h>
#include <security.h> #include <security.h>
#include <ntstatus.h> #include <ntstatus.h>
#include <malloc.h>
#include "inc\unistd.h" #include "inc\unistd.h"
#include "inc\sys\stat.h" #include "inc\sys\stat.h"
@ -56,12 +56,9 @@
#include "inc\sys\ioctl.h" #include "inc\sys\ioctl.h"
#include "inc\fcntl.h" #include "inc\fcntl.h"
#include "inc\utf.h" #include "inc\utf.h"
#include "signal_internal.h"
#include "misc_internal.h"
#include "debug.h" #include "debug.h"
#include "w32fd.h" #include "w32fd.h"
#include "inc\string.h" #include "inc\string.h"
#include "inc\grp.h"
#include "inc\time.h" #include "inc\time.h"
#include <wchar.h> #include <wchar.h>
@ -746,20 +743,15 @@ w32_rename(const char *old_name, const char *new_name)
return -1; return -1;
/* /*
* To be consistent with POSIX rename(), * To be consistent with POSIX rename(), if the new_name is directory
* 1) if the new_name is file, then delete it so that _wrename will succeed. * and it is empty then delete it so that MoveFileEx will succeed.
* 2) if the new_name is directory and it is empty then delete it so that _wrename will succeed.
*/ */
struct _stat64 st_new; struct _stat64 st_new;
struct _stat64 st_old; struct _stat64 st_old;
if ((fileio_stat(new_name, &st_new) != -1) && if ((fileio_stat(new_name, &st_new) != -1) &&
(fileio_stat(old_name, &st_old) != -1)) { (fileio_stat(old_name, &st_old) != -1) &&
if (((st_old.st_mode & _S_IFMT) == _S_IFREG) && ((st_old.st_mode & _S_IFMT) == _S_IFDIR) &&
((st_new.st_mode & _S_IFMT) == _S_IFREG)) ((st_new.st_mode & _S_IFMT) == _S_IFDIR)) {
w32_unlink(new_name);
if (((st_old.st_mode & _S_IFMT) == _S_IFDIR) &&
((st_new.st_mode & _S_IFMT) == _S_IFDIR)) {
DIR *dirp = opendir(new_name); DIR *dirp = opendir(new_name);
if (NULL != dirp) { if (NULL != dirp) {
struct dirent *dp = readdir(dirp); struct dirent *dp = readdir(dirp);
@ -767,15 +759,21 @@ w32_rename(const char *old_name, const char *new_name)
if (dp == NULL) if (dp == NULL)
w32_rmdir(new_name); w32_rmdir(new_name);
}
} }
} }
int returnStatus = _wrename(resolvedOldPathName_utf16, resolvedNewPathName_utf16); const int returnStatus = MoveFileExW(resolvedOldPathName_utf16, resolvedNewPathName_utf16, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED);
free(resolvedOldPathName_utf16); free(resolvedOldPathName_utf16);
free(resolvedNewPathName_utf16); free(resolvedNewPathName_utf16);
return returnStatus; /* Adjust errors and return codes to be consistent with rename() syscall */
if (returnStatus == 0) {
errno = errno_from_Win32LastError();
return -1;
}
return 0;
} }
int int