BLI_fileops: Harmonize 'rename' behaviors accross platforms.
This commit aim at making the behaviors of `BLI_rename` and `BLI_rename_overwrite` more consistent and coherent across all supported platforms. * `BLI_rename` now only succeeds in case the target `to` path does not exists (similar to Windows `rename` behavior). * `BLI_rename_overwrite` allows to replace an existing target `to` file or (empty) directory (similar to Unix `rename` behavior). NOTE: In case the target is open by some process on the system, trying to overwrite it will still fail on Windows, while it should succeed on Unix-like systems. The main change for Windows is the usage of `MoveFileExW` instead of `_wrename`, which allows for 'native support' of file overwrite (using the `MOVEFILE_REPLACE_EXISTING` flag). Directories still need to be explicitly removed though. The main change for *nix systems is the use of `renamex_np` (OSX) or `renameat2` (most Linux systems) to allow forbidding renaming to an already existing target in an 'atomic' way. NOTE: While this commit aims at avoiding the TOC/TOU problem as much as possible by using available system's primitives for most common cases, there are some situations where race conditions (filesystem changes between checks on FS state, and actual rename operation) remain possible. Pull Request: https://projects.blender.org/blender/blender/pulls/115096
This commit is contained in:
committed by
Bastien Montagne
parent
dfe1a7d039
commit
050d48edfc
@@ -72,14 +72,17 @@ int uaccess(const char *filename, int mode)
|
||||
return r;
|
||||
}
|
||||
|
||||
int urename(const char *oldname, const char *newname)
|
||||
int urename(const char *oldname, const char *newname, const bool do_replace)
|
||||
{
|
||||
int r = -1;
|
||||
UTF16_ENCODE(oldname);
|
||||
UTF16_ENCODE(newname);
|
||||
|
||||
if (oldname_16 && newname_16) {
|
||||
r = _wrename(oldname_16, newname_16);
|
||||
/* Closer to UNIX `rename` behavior, as it at least allows to replace an existing file.
|
||||
* Return value logic is inverted however (returns non-zero on sucess, 0 on failure).
|
||||
* Note that the operation will still fail if the 'newname' existing file is opened anywhere. */
|
||||
r = (MoveFileExW(oldname_16, newname_16, do_replace ? MOVEFILE_REPLACE_EXISTING : 0) == 0);
|
||||
}
|
||||
|
||||
UTF16_UN_ENCODE(newname);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
FILE *ufopen(const char *filename, const char *mode);
|
||||
int uopen(const char *filename, int oflag, int pmode);
|
||||
int uaccess(const char *filename, int mode);
|
||||
int urename(const char *oldname, const char *newname);
|
||||
int urename(const char *oldname, const char *newname, const bool do_replace);
|
||||
|
||||
char *u_alloc_getenv(const char *varname);
|
||||
void u_free_getenv(char *val);
|
||||
|
||||
Reference in New Issue
Block a user