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
175 lines
3.1 KiB
C++
175 lines
3.1 KiB
C++
/* SPDX-FileCopyrightText: 2012 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup intern_utf_conv
|
|
*/
|
|
|
|
#ifndef _WIN32_IE
|
|
# define _WIN32_IE 0x0501
|
|
#endif
|
|
|
|
#include "utf_winfunc.hh"
|
|
#include "utfconv.hh"
|
|
#include <io.h>
|
|
#include <wchar.h>
|
|
#include <windows.h>
|
|
|
|
FILE *ufopen(const char *filename, const char *mode)
|
|
{
|
|
FILE *f = NULL;
|
|
UTF16_ENCODE(filename);
|
|
UTF16_ENCODE(mode);
|
|
|
|
if (filename_16 && mode_16) {
|
|
f = _wfopen(filename_16, mode_16);
|
|
}
|
|
|
|
UTF16_UN_ENCODE(mode);
|
|
UTF16_UN_ENCODE(filename);
|
|
|
|
if (!f) {
|
|
if ((f = fopen(filename, mode))) {
|
|
printf("WARNING: %s is not utf path. Please update it.\n", filename);
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
int uopen(const char *filename, int oflag, int pmode)
|
|
{
|
|
int f = -1;
|
|
UTF16_ENCODE(filename);
|
|
|
|
if (filename_16) {
|
|
f = _wopen(filename_16, oflag, pmode);
|
|
}
|
|
|
|
UTF16_UN_ENCODE(filename);
|
|
|
|
if (f == -1) {
|
|
if ((f = open(filename, oflag, pmode)) != -1) {
|
|
printf("WARNING: %s is not utf path. Please update it.\n", filename);
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
int uaccess(const char *filename, int mode)
|
|
{
|
|
int r = -1;
|
|
UTF16_ENCODE(filename);
|
|
|
|
if (filename_16) {
|
|
r = _waccess(filename_16, mode);
|
|
}
|
|
|
|
UTF16_UN_ENCODE(filename);
|
|
|
|
return r;
|
|
}
|
|
|
|
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) {
|
|
/* 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);
|
|
UTF16_UN_ENCODE(oldname);
|
|
return r;
|
|
}
|
|
|
|
int umkdir(const char *pathname)
|
|
{
|
|
|
|
BOOL r = 0;
|
|
UTF16_ENCODE(pathname);
|
|
|
|
if (pathname_16) {
|
|
r = CreateDirectoryW(pathname_16, NULL);
|
|
}
|
|
|
|
UTF16_UN_ENCODE(pathname);
|
|
|
|
return r ? 0 : -1;
|
|
}
|
|
|
|
char *u_alloc_getenv(const char *varname)
|
|
{
|
|
char *r = 0;
|
|
wchar_t *str;
|
|
UTF16_ENCODE(varname);
|
|
if (varname_16) {
|
|
str = _wgetenv(varname_16);
|
|
r = alloc_utf_8_from_16(str, 0);
|
|
}
|
|
UTF16_UN_ENCODE(varname);
|
|
|
|
return r;
|
|
}
|
|
void u_free_getenv(char *val)
|
|
{
|
|
free(val);
|
|
}
|
|
|
|
int uput_getenv(const char *varname, char *value, size_t buffsize)
|
|
{
|
|
int r = 0;
|
|
wchar_t *str;
|
|
|
|
if (!buffsize) {
|
|
return r;
|
|
}
|
|
|
|
UTF16_ENCODE(varname);
|
|
if (varname_16) {
|
|
str = _wgetenv(varname_16);
|
|
conv_utf_16_to_8(str, value, buffsize);
|
|
r = 1;
|
|
}
|
|
UTF16_UN_ENCODE(varname);
|
|
|
|
if (!r) {
|
|
value[0] = 0;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
int uputenv(const char *name, const char *value)
|
|
{
|
|
int r = -1;
|
|
UTF16_ENCODE(name);
|
|
|
|
if (value) {
|
|
/* set */
|
|
UTF16_ENCODE(value);
|
|
|
|
if (name_16 && value_16) {
|
|
r = (SetEnvironmentVariableW(name_16, value_16) != 0) ? 0 : -1;
|
|
}
|
|
UTF16_UN_ENCODE(value);
|
|
}
|
|
else {
|
|
/* clear */
|
|
if (name_16) {
|
|
r = (SetEnvironmentVariableW(name_16, NULL) != 0) ? 0 : -1;
|
|
}
|
|
}
|
|
|
|
UTF16_UN_ENCODE(name);
|
|
|
|
return r;
|
|
}
|