alliedmodders / sourcemod

SourceMod - Source Engine Scripting and Administration
http://www.sourcemod.net/
991 stars 428 forks source link

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

Open bottiger1 opened 1 year ago

bottiger1 commented 1 year ago

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.

asherkin commented 1 year ago

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.

bottiger1 commented 1 year ago

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

Mooshua commented 1 year ago

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.

bottiger1 commented 1 year ago

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.

Mooshua commented 1 year ago

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.

bottiger1 commented 1 year ago

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.

Alienmario commented 1 year ago

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.

bottiger1 commented 1 year ago

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

dragokas commented 1 year ago

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;
}
bottiger1 commented 1 year ago

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