From 67cb6367e1a78d4a3ce63962f1b913ec61c4c402 Mon Sep 17 00:00:00 2001 From: SGrottel Date: Tue, 31 Mar 2026 17:43:38 +0200 Subject: [PATCH 1/3] Appartently even on Linux strings should be marshaled as Unicodes in CSharp Extended test for a exec binary search with unicode charaters in the name. --- Dockerfile | 2 +- FindExecutable/FindExecutable.cs | 4 +- Program.cs | 76 ++++++++++++++++++++++++++++---- 3 files changed, 71 insertions(+), 11 deletions(-) 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/FindExecutable.cs b/FindExecutable/FindExecutable.cs index 3ecb700..ad53a53 100644 --- a/FindExecutable/FindExecutable.cs +++ b/FindExecutable/FindExecutable.cs @@ -164,6 +164,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 +205,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..a51d86b 100644 --- a/Program.cs +++ b/Program.cs @@ -7,19 +7,35 @@ 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; - string[] executables = new string[] { + retval = Math.Max(retval, TestSearchGit()); + + retval = Math.Max(retval, TestUnicodeFile()); + + Console.WriteLine("done."); + if (retval != 0) + { + Console.WriteLine($"exit code: {retval}"); + } + return retval; + } + + static int TestSearchGit() + { + string[] executables = [ "git.exe", "git" - }; + ]; foreach (string executable in executables) { @@ -43,22 +59,64 @@ static int Main(string[] args) else { Console.Error.WriteLine("NOT FOUND"); - retval = 1; + return 1; } } catch (Exception e) { Console.Error.WriteLine($"FAILED, Exception: {e}"); - retval = 2; + return 2; } } - Console.WriteLine("done."); - if (retval != 0) + 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($"exit code: {retval}"); + 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; } - return retval; + + 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; } + } } From c316bc16a7dbc096d42defe2ad5c8dba5a04d100 Mon Sep 17 00:00:00 2001 From: SGrottel Date: Tue, 31 Mar 2026 18:05:54 +0200 Subject: [PATCH 2/3] Patch version bump --- FindExecutable/FindExecutable.cs | 2 ++ SGrottel.FindExecutable.nuspec | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/FindExecutable/FindExecutable.cs b/FindExecutable/FindExecutable.cs index ad53a53..5c157b3 100644 --- a/FindExecutable/FindExecutable.cs +++ b/FindExecutable/FindExecutable.cs @@ -25,6 +25,8 @@ // // Version history: // +// v1.0.2 -- 2026-03-31 +// resolved further finding by code analyzer // v1.0.1 -- 2026-02-22 // resolved findings by scanners // v1.0 -- 2025-05-19 diff --git a/SGrottel.FindExecutable.nuspec b/SGrottel.FindExecutable.nuspec index 205a909..28a2846 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 From 59a4089ebec2d5ed70e2d4b595ca22ed20ce3ad2 Mon Sep 17 00:00:00 2001 From: SGrottel Date: Wed, 1 Apr 2026 08:44:14 +0200 Subject: [PATCH 3/3] Removed obsolete ComponentSource.json --- FindExecutable/ComponentSource.json | 17 --- FindExecutable/FindExecutable.cs | 2 +- Program.cs | 170 ++++++++++++++-------------- SGrottel.FindExecutable.nuspec | 2 - 4 files changed, 86 insertions(+), 105 deletions(-) delete mode 100644 FindExecutable/ComponentSource.json 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 5c157b3..0ff3b0d 100644 --- a/FindExecutable/FindExecutable.cs +++ b/FindExecutable/FindExecutable.cs @@ -25,7 +25,7 @@ // // Version history: // -// v1.0.2 -- 2026-03-31 +// v1.0.2 -- 2026-04-01 // resolved further finding by code analyzer // v1.0.1 -- 2026-02-22 // resolved findings by scanners diff --git a/Program.cs b/Program.cs index a51d86b..33ecb62 100644 --- a/Program.cs +++ b/Program.cs @@ -1,89 +1,89 @@ -// -// 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) +// +// 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."); + 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; - } - - static int TestSearchGit() + } + 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; - } - } - + 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() + } + + 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); - } - + const string unicodeExec = "まじかよ。.exe"; + + if (File.Exists(unicodeExec)) + { + File.Delete(unicodeExec); + } + string unicodeExecPath = Path.Join(AppContext.BaseDirectory, unicodeExec); string? gitFullPath = FindExecutable.FullPath(gitExec); @@ -93,30 +93,30 @@ static int TestUnicodeFile() return 5; } - File.Copy(gitFullPath, unicodeExecPath); - + File.Copy(gitFullPath, unicodeExecPath); + if (!OperatingSystem.IsWindows()) { File.SetUnixFileMode(unicodeExecPath, File.GetUnixFileMode(gitFullPath)); } - if (!FindExecutable.IsExecutable(unicodeExecPath)) + 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 28a2846..1931ca0 100644 --- a/SGrottel.FindExecutable.nuspec +++ b/SGrottel.FindExecutable.nuspec @@ -20,7 +20,6 @@ - @@ -28,7 +27,6 @@ -