sourcemod icon indicating copy to clipboard operation
sourcemod copied to clipboard

No fast way to find correct case or real name for a file

Open bottiger1 opened this issue 2 years ago • 10 comments

So today we had a map in the map list in all caps while the file itself was in lowercase. Everyone on the server got kicked because our fast download server is running on Linux is case sensitive so no one could download the map.

I did a few tests and found out sourcemod functions like IsMapValid and FileExists are not case sensitive. The only way to find out the correct case for a map file I found is to use OpenDirectory and iterate through every single map file and do string comparison. While this works, it is slow taking 1-2 seconds and I don't consider ourselves to have a particularly large number of maps.

Is there a better solution that I am missing? What solution could be done to convert a valve file system path to the real one with correct casing? I looked at functions for the Valve file system and it seems like every function such as RelativePathToFullPath converts everything to lowercase.

bottiger1 avatar Jan 13 '23 00:01 bottiger1

The engine very intentionally works like this since Valve started supporting Linux clients - you probably want to make your web server handle case-insensitivity rather than fighting with the engine.

asherkin avatar Jan 13 '23 00:01 asherkin

There doesn't seem to be a way to make nginx case insensitive.

bottiger1 avatar Jan 13 '23 00:01 bottiger1

You could potentially use OpenResty (NGINX fork with Lua) to route any uppercase requests to their lowercase variant. Here’s an example of rerouting requests using OpenResty (from their docs):


 location /other {
     content_by_lua_block {
         ngx.say("dog = ", ngx.var.dog)
         ngx.say("cat = ", ngx.var.cat)
     }
 }

 location /lua {
     set $dog '';
     set $cat '';
     content_by_lua_block {
         res = ngx.location.capture("/other",
             { vars = { dog = "hello", cat = 32 }});

         ngx.print(res.body)
     }
 }

Respectfully, I’m not sure why this is really an issue for you given how preventable and easy to fix it is. Undoubtedly it could use some better documentation.

Mooshua avatar Jan 13 '23 01:01 Mooshua

I'm not sure why you think it is so preventable. Fixable sure? But mistakes happen and as soon as they happen, the entire server gets killed and takes forever to repopulate.

If you have random people adding maps, someone is eventually going to make a mistake and add something with the wrong case. And if they don't have root access, then that server is effectively dead for a long time. Changing to use a random webserver to fix this issue seems more like overkill to me.

bottiger1 avatar Jan 13 '23 02:01 bottiger1

Fixable sure? But mistakes happen and as soon as they happen, the entire server gets killed and takes forever to repopulate.

Completely agree, But as asherkin notes, at that point you are fighting the engine. It's going to be easier to have the web server accept and handle invalid casing than changing or patching intended behavior Valve purposefully implemented.

Changing to use a random webserver to fix this issue seems more like overkill to me.

OpenResty is not just a "random webserver"--it's a fork of NGINX and the third most used server today. I'd suggest at least trying it--It's probably going to be your easiest & quickest solution.

Mooshua avatar Jan 13 '23 07:01 Mooshua

OpenResty is a random webserver, I've never heard about it until now, and being the 3rd most used web server is meaningless when the top 2 account for over 50%. It is also not available on apt which means it will be hassle to maintain as well.

I also don't believe the snippet you've pasted actually fixes the issue. Simply converting everything to lowercase does not fix the problem, someone could easily type the map name in lowercase while the file itself has uppercase. Slapping lua into nginx doesn't magically give you case insensitive file matching either, it still uses the Linux OS file system to locate files.

bottiger1 avatar Jan 14 '23 01:01 bottiger1

This is not a solution alone, so it probably won't help. But just in case you want it, I have written (and never used) a plugin which hooks Host_Changelevel and converts map names to lowercase.

Alienmario avatar Jan 30 '23 19:01 Alienmario

As I just mentioned in the previous comment, that doesn't help in the case where the map randomly has upper case.

bottiger1 avatar Jan 30 '23 19:01 bottiger1

I'm using this walkaround in my plugins:

bool IsMapValidEx(char[] map)
{
	if( map[0] == 0 ) return false;
	static char path[PLATFORM_MAX_PATH];
	return FindMap(map, path, sizeof(path)) == FindMap_Found;
}

dragokas avatar Feb 02 '23 14:02 dragokas

I just tested that, it does not return the correct case of the file.

char path[256];
FindMap("cTF_2fOrT", path, sizeof(path));
PrintToServer("result: %s", path); // prints cTF_2fOrT, not ctf_2fort

bottiger1 avatar Feb 02 '23 20:02 bottiger1