Problem locating unix executables #MG5

It seems to work from my Windows machine:
$ type java
java is C:\Program Files\Eclipse Adoptium\jdk-21.0.6.7-hotspot\bin\java.exe
$

But doesn’t work with the tester’s Linux machine:

remote: [tester::#MG5] Running ./your_program.sh
remote: [your-program] $ type cat
remote: [your-program] cat: not found
remote: [tester::#MG5] ^ Line does not match expected value.
remote: [tester::#MG5] Expected: "cat is /bin/cat"
remote: [tester::#MG5] Received: "cat: not found"
remote: [your-program] $
remote: [tester::#MG5] Assertion failed.
remote: [tester::#MG5] Test failed

Code:

// Builtin.cs

public void Type(object[] module_name)
{
    string name = module_name[0].ToString();
    if (ValidateBuiltinName(name))
    {
        Console.WriteLine($"{name} is a shell builtin");
        return;
    }

    string path = Environment.GetEnvironmentVariable("PATH");
    IEnumerable<string> folders = path.Split(Path.PathSeparator);

    foreach (string folder in folders)
    {
        DirectoryInfo directory = new DirectoryInfo(folder);
        try
        {
            foreach (FileInfo file in directory.GetFiles())
            {
                if (file.Name.StartsWith(name) && u.IsFileExecutable(file.FullName))
                {
                    Console.WriteLine($"{name} is {file.FullName}");
                    return;
                }
            }
        } catch (DirectoryNotFoundException ex) { }

        
    }

    Console.WriteLine($"{module_name[0]}: not found");
}
// Utils.cs

public bool IsFileExecutable(string filePath)
{

    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
        if (new string[] { ".dll" }.Contains(new FileInfo(filePath).Extension))
        {
            return false;
        }

        byte[] firstBytes = new byte[2];

        try
        {
            using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read))
            {
                if (fs.Length >= 2)
                {
                    fs.Read(firstBytes, 0, 2);
                }
            }
        }
        catch
        {
            return false;
        }

        return Encoding.UTF8.GetString(firstBytes) == "MZ"; 
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { 
        UnixFileMode mode = File.GetUnixFileMode(filePath);
        if (mode == UnixFileMode.OtherExecute || mode == UnixFileMode.UserExecute || mode == UnixFileMode.GroupExecute)
        {
            return true;
        }
    }

    return false;
}

I don’t have a Linux machine to test on so this is rather inconvenient :confused:

Hmm. Maybe investigate File.GetUnixFileMode. It looks like it returns a bitmask of capabilities but your comparison is checking 3 particular exact bitmask matches (1, 8, or 64). Would your check ever pass if the owner has UserRead(256) permission?

1 Like

Hey @salmon-571, you’ll want to use bitwise checks rather than equality comparisons on UnixFileMode.

I’d recommend using WSL if you’re testing this locally,

Let me know if you’d like further clarification!

@salmon-571 Just curious, were you able to run C# code using Java? :thinking:

Thank you for your help, I’ll have to try this when I get home.

Also, no I was not able to do that. I just used java as an example of a program on my PATH because I don’t have cat.

1 Like

No, I forgot to add this check to my if statement. Thanks for reminding me :sweat_smile:

Here is the function fixed for those that are wondering:

public bool IsFileExecutable(string filePath)
{

    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
        if (new string[] { ".dll" }.Contains(new FileInfo(filePath).Extension))
        {
            return false;
        }

        byte[] firstBytes = new byte[2];

        try
        {
            using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read))
            {
                if (fs.Length >= 2)
                {
                    fs.Read(firstBytes, 0, 2);
                }
            }
        }
        catch
        {
            return false;
        }

        return Encoding.UTF8.GetString(firstBytes) == "MZ"; 
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { 
        UnixFileMode mode = File.GetUnixFileMode(filePath);
        UnixFileMode perms = UnixFileMode.UserExecute | UnixFileMode.UserRead;
        return (mode & perms) == perms;
    }

    return false;
}
1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.