【问题标题】:File permissions on Linux/Unix with .NET Core使用 .NET Core 在 Linux/Unix 上的文件权限
【发布时间】:2017-12-21 06:33:41
【问题描述】:

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

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

【问题讨论】:

  • Microsoft 在 Windows 上使用他们的文件权限模型并将其转换为 Linux/UNIX。所以对chmod的调用是内部的,github.com/dotnet/corefx/blob/…只用在github.com/dotnet/corefx/blob/…所以在你的情况下,你必须把644翻译成对应的Windows文件权限,然后用Windows的方式来操作文件。

标签: c# .net asp.net-core .net-core


【解决方案1】:

目前,.NET Core 中没有内置 API。但是,.NET Core 团队正在努力使 Mono.Posix 在 .NET Core 上可用。这会公开 API 以在托管代码中执行此类操作。请参阅 https://github.com/dotnet/corefx/issues/15289https://github.com/dotnet/corefx/issues/3186。您可以在此处试用此 API 的早期版本:https://www.nuget.org/packages/Mono.Posix.NETStandard/1.0.0-beta1

    var unixFileInfo = new Mono.Unix.UnixFileInfo("test.txt");
    // set file permission to 644
    unixFileInfo.FileAccessPermissions =
        FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite
        | FileAccessPermissions.GroupRead
        | FileAccessPermissions.OtherRead;

如果您不想使用 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));
    }
}

【讨论】:

  • 注意 - NuGet 包已经过测试版:nuget.org/packages/Mono.Posix.NETStandard
  • 我发现我必须发出unixFileInfo.Refresh() 才能立即将更改提交到文件系统。否则,这些变化将在某个未指定的时间后显现出来。好奇有没有其他人看过?
  • 您是否使用 .NetCore 运行本机代码示例?
【解决方案2】:

我通过启动一个新进程并执行 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 命令。

【讨论】:

    【解决方案3】:

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

    public static async ValueTask SetPermissionsAsync(string filePath, string permissions) =>
        await Cli.Wrap("/bin/bash")
            .WithArguments(new[] {"-c", $"chmod {permissions} {filePath}"})
            .ExecuteAsync();
    

    自动处理转义、错误等。

    【讨论】:

      【解决方案4】:

      这是一个简单的 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;
              }
      }
      

      【讨论】:

      • 原来的帖子是几年前的,所以请检查一下“bash/chmod”和 Mono.Postix 包是否有其他替代方案。
      猜你喜欢
      • 2014-10-01
      • 2017-05-26
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 2013-09-09
      • 2020-12-02
      • 1970-01-01
      • 2018-12-12
      相关资源
      最近更新 更多