Selaa lähdekoodia

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.
Valentin Cocaud 6 vuotta sitten
vanhempi
commit
c09731c413

+ 41 - 0
drivers/unix/file_access_unix.cpp

@@ -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.");
 

+ 4 - 0
drivers/unix/file_access_unix.h

@@ -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;
 

+ 1 - 1
drivers/windows/file_access_windows.cpp

@@ -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://,