diff --git a/Dockerfile b/Dockerfile index ab548b7..cb79bdd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # This docker can be used to test the linux implementation of FindExecutable # # On a Windows dev PC run: -# docker build -t sgr/findexecutabletest . +# docker build -t sgr/findexecutabletest . # docker run --rm -v ".\bin\Debug\net10.0:/myapp" -t sgr/findexecutabletest # # Adjust path of the volume mount if you are to test other build flavors. diff --git a/FindExecutable/ComponentSource.json b/FindExecutable/ComponentSource.json deleted file mode 100644 index 6ee736b..0000000 --- a/FindExecutable/ComponentSource.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "_type": "ComponentSourceManifest", - "_version": 1, - "components": [ - { - "name": "SGrottel FindExecutable", - "source": [ - { - "type": "git", - "url": "https://www.github.com/sgrottel/FindExecutable", - "hash": "7f50fbe3e3211719817d76f637ea01cb1d410447", - "path": "FindExecutable" - } - ] - } - ] -} diff --git a/FindExecutable/FindExecutable.cs b/FindExecutable/FindExecutable.cs index 3ecb700..0ff3b0d 100644 --- a/FindExecutable/FindExecutable.cs +++ b/FindExecutable/FindExecutable.cs @@ -25,6 +25,8 @@ // // Version history: // +// v1.0.2 -- 2026-04-01 +// resolved further finding by code analyzer // v1.0.1 -- 2026-02-22 // resolved findings by scanners // v1.0 -- 2025-05-19 @@ -164,6 +166,7 @@ public static class FindExecutable #region Test if File is Executable #region Windows P/Invoke + [SupportedOSPlatform("Windows")] [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, IntPtr psfi, uint cbSizeFileInfo, uint uFlags); private const uint SHGFI_EXETYPE = 0x000002000; @@ -204,7 +207,8 @@ private static bool IsExecutableOnWindow(string path) } #region Linux P/Invoke - [DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)] + [UnsupportedOSPlatform("Windows")] + [DllImport("libc", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int access(string pathname, int mode); // https://codebrowser.dev/glibc/glibc/posix/unistd.h.html#283 private const int X_OK = 1; diff --git a/Program.cs b/Program.cs index a741aca..33ecb62 100644 --- a/Program.cs +++ b/Program.cs @@ -1,64 +1,122 @@ -// -// Run Docker/Linux test with: -// -// docker build -t sgr/findexecutable . -// docker run --rm sgr/findexecutable -// - -using System; -using System.IO; - -namespace FindExecutable -{ - internal class Program - { - static int Main(string[] args) - { - int retval = 0; - - string[] executables = new string[] { - "git.exe", - "git" - }; - - foreach (string executable in executables) - { - try - { - Console.WriteLine($"Searching for: {executable}"); - - string? fullPath = FindExecutable.FullPath(executable); - - if (fullPath != null) - { - if (Path.IsPathFullyQualified(fullPath)) - { - Console.WriteLine($"FOUND: {fullPath}"); - } - else - { - Console.WriteLine($"FOUND w/ WARNING: non-full path, {fullPath}"); - } - } - else - { - Console.Error.WriteLine("NOT FOUND"); - retval = 1; - } - } - catch (Exception e) - { - Console.Error.WriteLine($"FAILED, Exception: {e}"); - retval = 2; - } - } - - Console.WriteLine("done."); +// +// Run Docker/Linux test with: +// +// docker build -t sgr/findexecutable . +// docker run --rm sgr/findexecutable +// + +using System; +using System.IO; +using System.Reflection; + +namespace FindExecutable +{ + internal class Program + { + static int Main(string[] args) + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + int retval = 0; + + retval = Math.Max(retval, TestSearchGit()); + + retval = Math.Max(retval, TestUnicodeFile()); + + Console.WriteLine("done."); if (retval != 0) { Console.WriteLine($"exit code: {retval}"); - } - return retval; - } - } -} + } + return retval; + } + + static int TestSearchGit() + { + string[] executables = [ + "git.exe", + "git" + ]; + + foreach (string executable in executables) + { + try + { + Console.WriteLine($"Searching for: {executable}"); + + string? fullPath = FindExecutable.FullPath(executable); + + if (fullPath != null) + { + if (Path.IsPathFullyQualified(fullPath)) + { + Console.WriteLine($"FOUND: {fullPath}"); + } + else + { + Console.WriteLine($"FOUND w/ WARNING: non-full path, {fullPath}"); + } + } + else + { + Console.Error.WriteLine("NOT FOUND"); + return 1; + } + } + catch (Exception e) + { + Console.Error.WriteLine($"FAILED, Exception: {e}"); + return 2; + } + } + + return 0; + } + + static int TestUnicodeFile() + { + Console.WriteLine("Searching for an (artificial) executable with a unicode name:"); + + const string gitExec = "git"; + const string unicodeExec = "まじかよ。.exe"; + + if (File.Exists(unicodeExec)) + { + File.Delete(unicodeExec); + } + + string unicodeExecPath = Path.Join(AppContext.BaseDirectory, unicodeExec); + string? gitFullPath = FindExecutable.FullPath(gitExec); + + if (gitFullPath == null) + { + Console.WriteLine("Failed to find git exec as test subject"); + return 5; + } + + File.Copy(gitFullPath, unicodeExecPath); + + if (!OperatingSystem.IsWindows()) + { + File.SetUnixFileMode(unicodeExecPath, File.GetUnixFileMode(gitFullPath)); + } + + if (!FindExecutable.IsExecutable(unicodeExecPath)) + { + Console.WriteLine($"Failed to setup the unicode executable file name: {unicodeExecPath}"); + return 3; + } + + string? findIt = FindExecutable.FullPath(unicodeExec, includeCurrentDirectory: true); + if (string.IsNullOrEmpty(findIt)) + { + Console.WriteLine($"Failed to find the unicode executable file name: {unicodeExec}"); + return 4; + } + + Console.WriteLine($"FOUND: {findIt}"); + + return 0; + } + + } +} diff --git a/SGrottel.FindExecutable.nuspec b/SGrottel.FindExecutable.nuspec index 205a909..1931ca0 100644 --- a/SGrottel.FindExecutable.nuspec +++ b/SGrottel.FindExecutable.nuspec @@ -6,7 +6,7 @@ SGrottel.FindExecutable - 1.0.1 + 1.0.2 SGrottel.FindExecutable SGrottel SGrottel @@ -20,7 +20,6 @@ - @@ -28,7 +27,6 @@ -