C# 具有.NET内核的Linux/Unix上的文件权限

C# 具有.NET内核的Linux/Unix上的文件权限,c#,.net,asp.net-core,.net-core,C#,.net,Asp.net Core,.net Core,我正在尝试学习如何使用.NET内核在Linux/Unix上设置文件权限。我已经在这里找到了一个问题,它为我指明了System.IO.FileSystem的方向,但是我似乎找不到任何关于如何使用它的文档 简而言之,我想从一个只在Linux上运行的.NET Core应用程序中chmod一个文件644,但我不知道如何继续。目前,.NET Core中没有用于此的内置API。然而,.NET核心团队正在努力使Mono.Posix在.NET核心上可用。这将公开API以在托管代码中执行此类操作。见和。您可以在此

我正在尝试学习如何使用.NET内核在Linux/Unix上设置文件权限。我已经在这里找到了一个问题,它为我指明了System.IO.FileSystem的方向,但是我似乎找不到任何关于如何使用它的文档


简而言之,我想从一个只在Linux上运行的.NET Core应用程序中chmod一个文件644,但我不知道如何继续。

目前,.NET Core中没有用于此的内置API。然而,.NET核心团队正在努力使
Mono.Posix
在.NET核心上可用。这将公开API以在托管代码中执行此类操作。见和。您可以在此处尝试此API的早期版本:

如果不想使用Mono.Posix,可以通过调用本机代码来实现相同的功能。使用P/Invoke,您可以从
libc
调用
chmod
函数。有关本机API的更多详细信息,请参见
man 2 chmod

using System;
using System.IO;
using System.Runtime.InteropServices;
using static System.Console;

class Program
{
    [DllImport("libc", SetLastError = true)]
    private static extern int chmod(string pathname, int mode);

    // user permissions
    const int S_IRUSR = 0x100;
    const int S_IWUSR = 0x80;
    const int S_IXUSR = 0x40;

    // group permission
    const int S_IRGRP = 0x20;
    const int S_IWGRP = 0x10;
    const int S_IXGRP = 0x8;

    // other permissions
    const int S_IROTH = 0x4;
    const int S_IWOTH = 0x2;
    const int S_IXOTH = 0x1;

    static void Main(string[] args)
    {
        WriteLine("Setting permissions to 0755 on test.sh");
        const int _0755 =
            S_IRUSR | S_IXUSR | S_IWUSR
            | S_IRGRP | S_IXGRP
            | S_IROTH | S_IXOTH;
        WriteLine("Result = " + chmod(Path.GetFullPath("test.sh"), (int)_0755));

        WriteLine("Setting permissions to 0644 on sample.txt");
        const int _0644 =
            S_IRUSR | S_IWUSR
            | S_IRGRP
            | S_IROTH;
        WriteLine("Result = " + chmod(Path.GetFullPath("sample.txt"), _0644));

        WriteLine("Setting permissions to 0600 on secret.txt");
        const int _0600 = S_IRUSR | S_IWUSR;
        WriteLine("Result = " + chmod(Path.GetFullPath("secret.txt"), _0600));
    }
}

我通过启动一个新进程并执行bash
chmod
命令解决了这个问题

示例:

public static void Exec(string cmd)
{
    var escapedArgs = cmd.Replace("\"", "\\\"");
        
    using var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
            WindowStyle = ProcessWindowStyle.Hidden,
            FileName = "/bin/bash",
            Arguments = $"-c \"{escapedArgs}\""
        }
    };

    process.Start();
    process.WaitForExit();
}
然后:

Exec("chmod 644 /path/to/file.txt");

您还可以使用此
Exec
方法来运行任何其他类型的bash命令。

与@kspearrin建议的方法类似,但为了简单起见,请使用:

public静态异步值任务SetPermissionsAsync(字符串文件路径,字符串权限)=>
等待Cli.Wrap(“/bin/bash”)
.WithArguments(新[]{“-c”,$“chmod{permissions}{filePath}})
.ExecuteAsync();

自动处理转义、错误等。

这里有一个简单的chmod函数,可以在c#中使用,没有依赖性

// Returns true if success and false otherwise
// permissions can be an int or a string. For example it can also be +x, -x etc..
bool Chmod(string filePath, string permissions = "700", bool recursive = false)
{
        string cmd;
        if (recursive)
            cmd = $"chmod -R {permissions} {filePath}";
        else
            cmd = $"chmod {permissions} {filePath}";

        try
        {
            using (Process proc = Process.Start("/bin/bash", $"-c \"{cmd}\""))
            {
                proc.WaitForExit();
                return proc.ExitCode == 0;
            }
        }
        catch
        {
            return false;
        }
}

Microsoft在Windows上使用他们的文件权限模型,并将其转换为Linux/UNIX。因此,对
chmod
的调用是内部调用,并且仅用于So。在您的情况下,您必须将644转换为相应的Windows文件权限,然后使用Windows方式操作该文件。注意-NuGet软件包已过测试版:我发现我必须发布
unixFileInfo.Refresh()
立即将更改提交到文件系统。否则,这些更改将在稍后的某个未指定时间显示。好奇是否有人看到过这一点?您是否使用.NetCore运行本机代码示例?最初的帖子是几年前发布的,所以请登录查看“bash/chmod”和Mono.Postix包是否还有其他替代方案。
// Returns true if success and false otherwise
// permissions can be an int or a string. For example it can also be +x, -x etc..
bool Chmod(string filePath, string permissions = "700", bool recursive = false)
{
        string cmd;
        if (recursive)
            cmd = $"chmod -R {permissions} {filePath}";
        else
            cmd = $"chmod {permissions} {filePath}";

        try
        {
            using (Process proc = Process.Start("/bin/bash", $"-c \"{cmd}\""))
            {
                proc.WaitForExit();
                return proc.ExitCode == 0;
            }
        }
        catch
        {
            return false;
        }
}