Warn on filesystem case mismatch

When a file is opened with a wrong case, it can work on the developer system but break on a user system with a case-sensitive filesystem.

This will display a warning when it happens.

CAVEATS: It will also display the warning if a symlink is in the path.

Adapt warning if the file is a symlink. Avoid warning on symlinks.

Fix memory leak and avoid `lstat` usage.

Avoid exposing real_path when not in TOOLS_ENABLED mode.
This commit is contained in:
Valentin Cocaud 2019-01-09 10:24:23 +01:00 committed by K. S. Ernest (iFire) Lee
parent 87318a2fb7
commit c09731c413
3 changed files with 46 additions and 1 deletions

View File

@ -41,6 +41,11 @@
#include <sys/types.h>
#include <unistd.h>
#if defined(TOOLS_ENABLED)
#include <limits.h>
#include <stdlib.h>
#endif
void FileAccessUnix::check_errors() const {
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
@ -87,6 +92,22 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
}
}
#if defined(TOOLS_ENABLED)
if (p_mode_flags & READ) {
String real_path = get_real_path();
if (real_path != path) {
// Don't warn on symlinks, since they can be used to simply share addons on multiple projects.
if (real_path.to_lower() == path.to_lower()) {
// The File system is case insensitive, but other platforms can be sensitive to it
// To ease cross-platform development, we issue a warning if users try to access
// a file using the wrong case (which *works* on Windows and macOS, but won't on other
// platforms).
WARN_PRINT(vformat("Case mismatch opening requested file '%s', stored as '%s' in the filesystem. This file will not open when exported to other case-sensitive platforms.", path, real_path));
}
}
}
#endif
if (is_backup_save_enabled() && (p_mode_flags == WRITE)) {
save_path = path;
// Create a temporary file in the same directory as the target file.
@ -173,6 +194,26 @@ String FileAccessUnix::get_path_absolute() const {
return path;
}
#if defined(TOOLS_ENABLED)
String FileAccessUnix::get_real_path() const {
char *resolved_path = ::realpath(path.utf8().get_data(), nullptr);
if (!resolved_path) {
return path;
}
String result;
Error parse_ok = result.parse_utf8(resolved_path);
::free(resolved_path);
if (parse_ok != OK) {
return path;
}
return result.simplify_path();
}
#endif
void FileAccessUnix::seek(uint64_t p_position) {
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");

View File

@ -51,6 +51,10 @@ class FileAccessUnix : public FileAccess {
void _close();
#if defined(TOOLS_ENABLED)
String get_real_path() const; // Returns the resolved real path for the current open file.
#endif
public:
static CloseNotificationFunc close_notification_func;

View File

@ -127,7 +127,7 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
}
#ifdef TOOLS_ENABLED
// Windows is case insensitive, but all other platforms are sensitive to it
// Windows is case insensitive in the default configuration, but other platforms can be sensitive to it
// To ease cross-platform development, we issue a warning if users try to access
// a file using the wrong case (which *works* on Windows, but won't on other
// platforms), we only check for relative paths, or paths in res:// or user://,