Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 0 additions & 17 deletions FindExecutable/ComponentSource.json

This file was deleted.

6 changes: 5 additions & 1 deletion FindExecutable/FindExecutable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
180 changes: 119 additions & 61 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -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;
}

}
}
4 changes: 1 addition & 3 deletions SGrottel.FindExecutable.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<!-- package metadata -->
<metadata minClientVersion="3.3" >
<id>SGrottel.FindExecutable</id>
<version>1.0.1</version>
<version>1.0.2</version>
<title>SGrottel.FindExecutable</title>
<authors>SGrottel</authors>
<owners>SGrottel</owners>
Expand All @@ -20,15 +20,13 @@

<contentFiles>
<files include="cs/any/FindExecutable/FindExecutable.cs" />
<files include="cs/any/FindExecutable/ComponentSource.json" buildAction="None" />
<files include="cs/any/FindExecutable/LICENSE" buildAction="None" />
</contentFiles>
</metadata>

<!-- content -->
<files>
<file src="FindExecutable\FindExecutable.cs" target="contentFiles/cs/any/FindExecutable" />
<file src="FindExecutable\ComponentSource.json" target="contentFiles/cs/any/FindExecutable" />
<file src="LICENSE" target="contentFiles/cs/any/FindExecutable/LICENSE" />

<file src="package_readme.md" target="docs/README.md" />
Expand Down