Repository: godotengine/godot
File: editor/project_manager/project_dialog.cpp (C++)

Code before:
				n = d->get_next();
			}
			d->list_dir_end();

			if (!is_folder_empty) {
				_set_message(TTRC("The selected path is not empty. Choosing an empty folder is highly recommended."), MESSAGE_WARNING, target_path_input_type);
			}
		}
	}

	// Check if the target path is a subdirectory of original when duplicating
	if (mode == MODE_DUPLICATE) {
		String base_path = original_project_path;
		String duplicate_target = target_path;

		// Ensure the paths end with a slash
		if (!base_path.ends_with("/")) {
			base_path += "/";
		}

		if (!duplicate_target.ends_with("/")) {
			duplicate_target += "/";
		}

#ifdef WINDOWS_ENABLED
		// On Windows, make both lowercase for case-insensitive comparison
		base_path = base_path.to_lower();
		String target_lower = duplicate_target.to_lower();
		bool is_subdirectory = target_lower.begins_with(base_path);
		bool is_equal = base_path == target_lower;
#else
		// On Unix, paths are case-sensitive
		bool is_subdirectory = duplicate_target.begins_with(base_path);
		bool is_equal = base_path == duplicate_target;
#endif
		if (is_subdirectory || is_equal) {
			_set_message(TTRC("Cannot duplicate a project into itself."), MESSAGE_ERROR, target_path_input_type);
		}
	}
}

String ProjectDialog::_get_target_path() {
	if (mode == MODE_NEW || mode == MODE_INSTALL || mode == MODE_DUPLICATE) {
		return project_path->get_text();
	} else if (mode == MODE_IMPORT) {
		return install_path->get_text();
	} else {
		ERR_FAIL_V("");
	}
}
void ProjectDialog::_set_target_path(const String &p_text) {

Review comment (security):
Not only Windows is case-insensitive, you should use `DirAccess.is_case_sensitive()` instead.

Code after:
				n = d->get_next();
			}
			d->list_dir_end();

			if (!is_folder_empty) {
				_set_message(TTRC("The selected path is not empty. Choosing an empty folder is highly recommended."), MESSAGE_WARNING, target_path_input_type);
			}
		}
	}

	// Check if the target path is a subdirectory of original when duplicating
	if (mode == MODE_DUPLICATE) {
		String base_path = original_project_path;
		String duplicate_target = target_path;

		// Ensure the paths end with a slash
		if (!base_path.ends_with("/")) {
			base_path += "/";
		}

		if (!duplicate_target.ends_with("/")) {
			duplicate_target += "/";
		}

		bool is_subdirectory_or_equal;

		if (d->is_case_sensitive(base_path) || d->is_case_sensitive(duplicate_target)) {
			is_subdirectory_or_equal = duplicate_target.begins_with(base_path);
		} else {
			base_path = base_path.to_lower();
			String target_lower = duplicate_target.to_lower();
			is_subdirectory_or_equal = target_lower.begins_with(base_path);
		}

		if (is_subdirectory_or_equal) {
			_set_message(TTRC("Cannot duplicate a project into itself."), MESSAGE_ERROR, target_path_input_type);
		}
	}
}

String ProjectDialog::_get_target_path() {
	if (mode == MODE_NEW || mode == MODE_INSTALL || mode == MODE_DUPLICATE) {
		return project_path->get_text();
	} else if (mode == MODE_IMPORT) {
		return install_path->get_text();
	} else {
		ERR_FAIL_V("");
	}
}
void ProjectDialog::_set_target_path(const String &p_text) {
	if (mode == MODE_NEW || mode == MODE_INSTALL || mode == MODE_DUPLICATE) {