如何使用 p/invoke 在没有 Mono.Posix 的情况下在 .NET 5 / .NET 6 中获取 Linux 文件权限?

2023-11-27

我最近发现,我可以相对容易地从 .NET 进行 Linux 系统调用。

例如,看看我是否需要sudo我只是做了这样的签名:

internal class Syscall {

[DllImport("libc", SetLastError = true)]
internal static extern uint geteuid();

// ...
}
public static bool IsRoot => Syscall.geteuid() == 0;

整洁的。比其他一切都更容易和更快,对吗? 这是最简单的系统调用,其他使用字符串和结构。

经过一番深入研究文档并亲自测试后,我发现来自的字符串libc可以直接映射到string from char*默认情况下,编组器,大多数其他东西只需要使用一些手动映射的乐趣IntPtr到结构。

所以以类似的方式我快速映射chmod, chown, lchown, getgrnam, getpwnam, getuid, symlink。所有这些都在我的 Ubuntu VM 上进行了测试,有效。

我什至自己做了超级整洁Chmod与 shell 工作方式相同的实现chmod接受相对权限,例如u+wX。并遍历文件系统。

这就是我失去一个晚上的地方。我需要原始权限,我读到可以通过以下方式获得它们stat称呼。可能会出现什么问题?

首先我做了Stat结构使用Linux手册文档:https://man7.org/linux/man-pages/man2/stat.2.html

然后我做了相应的extern.

第一个惊喜:找不到入口点。

我挖啊挖啊,又挖了一些。直到我刚刚打开我的libc二进制并搜索类似的东西stat。答对了!我发现__xstat观点。就是这样,我更改了我的签名,我在文档中阅读了除了指定之外的内容ver参数(应设置为3) - 它应该有效完全相同的 to stat.

事实并非如此。调用通过,但是总是返回-1,不返回Stat结构。

然后我找到了一些资源__xstat它检查是否ver参数与内核版本匹配。诡异的!但我尝试通过5。因为这是我当前使用的内核版本。还有一些其他数字,例如“3”和“0”。没有运气。什么都不起作用。我也测试过__xstat64。同样的结果,我的意思是没有结果。

然后我在 GitHub 上发现了一个讨论.NET开发人员,那个召唤stat非常棘手,因为每个内核都不同。等待,WHAT!?

是的,我知道它在Mono.Posix.NETStandard 1.0.0包,我使用它并且它有效。 (这就是人们推荐的。)

但由于我刚刚学习平台调用“voodoo” - 我不能就这样离开它。为什么除了stat调用没有任何问题,为什么会出现异常?这是一个完全基本的事情。在“为什么”之后是“如何?”。

他们做到了Mono。我挖了进去MonoGitHub 上的资源发现,它是少数几个实际上没有调用的函数之一libc但来自他们自己在 C 中的汇编:https://github.com/mono/mono/blob/main/support/sys-stat.c

很有趣,但我仍然很难理解它是如何工作的。

顺便说一句,添加Mono我的项目将编译后的可执行 Linux x64 文件从 200kb 增加到 1200kb。字面上增加1个读取单个数字的功能!顺便说一句,它有一个许可证问题,包签名说MIT,链接的源文件说MPL。我的软件包要求用户接受这个奇怪的许可证。我的意思是,接受MIT,虽然我不太确定这是否真的MIT or MPL。我自己的包使用MIT.

那么 - 打电话时有哪些(其他)问题和陷阱libc来自点网?有没有更简单的调用方式stat()?是否有其他途径获取权限.NET?我想出了.NET它本身内部就是这样做的。它获取可从以下位置获得的文件权限FileInfo。然而,属性被“翻译”为Windows结构,并且大部分信息在翻译中丢失。

我最后一次尝试:

[DllImport("libc", SetLastError = true)]
internal static extern int __xstat(int ver, string path, out Stat stat);

internal struct Stat {

    public ulong st_dev;        // device
    public ulong st_ino;        // inode
    public uint st_mode;        // protection
    public ulong st_nlink;      // number of hard links
    public uint st_uid;         // user ID of owner
    public uint st_gid;         // group ID of owner
    public ulong st_rdev;       // device type (if inode device)
    public long st_size;        // total size, in bytes
    public long st_blksize;     // blocksize for filesystem I/O
    public long st_blocks;      // number of blocks allocated
    public long st_atime;       // time of last access
    public long st_mtime;       // time of last modification
    public long st_ctime;       // time of last status change
    public long st_atime_nsec;  // Timespec.tv_nsec partner to st_atime
    public long st_mtime_nsec;  // Timespec.tv_nsec partner to st_mtime
    public long st_ctime_nsec;  // Timespec.tv_nsec partner to st_ctime

}

叫像Syscall.__xstat(5, path, out Stat stat)。退货-1对于我尝试过的任何路径。

当然

public static Permissions GetPermissions(string path) {
    if (Mono.Unix.Native.Syscall.stat(path, out var stat) != 0) throw new InvalidOperationException($"Stat call failed for {path}");
    return new Permissions((uint)stat.st_mode);
}

作品。它只需要 1MB 多;)我知道,这没什么,但我只是为了 1 个简单的函数而有外部依赖。

根据我的研究 -Stat结构因内核而异。我怀疑如果我尝试其他一些版本,其中一个最终会工作,但它根本不能解决问题,因为它可以在目标计算机上更新后停止工作。

我的猜测是,当 Linux 中需要并允许更改结构时,必须有一种通用接口/兼容性机制,允许用户在不详细了解特定目标机器上的系统和库版本的情况下获得权限。

我想libc只是类似的东西,但似乎要么不完全是这样,要么 Linux 中的其他地方有更高级别的接口,我在这里指的不是 shell ;)

我主要有Windows背景,我经常使用Windows p/invoke。我为 Windows 7 编写的大部分代码仍然可以在 Windows 11 上运行。旧Win32调用没有改变,除了一些非常系统 UI 特定的调用。


所以,我错误地发布了最后一个答案。我发现,libc二进制文件包含类似 __xstat 的内容,我称之为。

错误的!顾名思义,它是一种私有函数,旨在成为实现细节,而不是 API 的一部分。

所以我找到了另一个具有正常名称的函数:statx。它完全符合我的需要,这里有很好的记录:

https://man7.org/linux/man-pages/man2/statx.2.html

这是结构和值:https://code.woboq.org/qt5/include/bits/statx.h.html https://code.woboq.org/userspace/glibc/io/fcntl.h.html

TL;DR - 它有效。

我发现 -100 (AT_FDCWD) 传递为dirfd参数创建相对于当前工作目录的相对路径。

我还发现将零作为标志传递是有效的(相当于AT_STATX_SYNC_AS_STAT),并且该函数返回常规本地文件系统应有的内容。

所以这是代码:

[DllImport(LIBC, SetLastError = true)]
internal static extern int statx(int dirfd, string path, int flags, uint mask, out Statx data);

/// <summary>
/// POSIX statx data structure.
/// </summary>
internal struct Statx {

    /// <summary>
    /// Mask of bits indicating filled fields.
    /// </summary>
    internal uint Mask;
    /// <summary>
    /// Block size for filesystem I/O.
    /// </summary>
    internal uint BlockSize;
    /// <summary>
    /// Extra file attribute indicators
    /// </summary>
    internal ulong Attributes;
    /// <summary>
    /// Number of hard links.
    /// </summary>
    internal uint HardLinks;
    /// <summary>
    /// User ID of owner.
    /// </summary>
    internal uint Uid;
    /// <summary>
    /// Group ID of owner.
    /// </summary>
    internal uint Gid;
    /// <summary>
    /// File type and mode.
    /// </summary>
    internal ushort Mode;
    private ushort Padding01;
    /// <summary>
    /// Inode number.
    /// </summary>
    internal ulong Inode;
    /// <summary>
    /// Total size in bytes.
    /// </summary>
    internal ulong Size;
    /// <summary>
    /// Number of 512B blocks allocated.
    /// </summary>
    internal ulong Blocks;
    /// <summary>
    /// Mask to show what's supported in <see cref="Attributes"/>.
    /// </summary>
    internal ulong AttributesMask;
    /// <summary>
    /// Last access time.
    /// </summary>
    internal StatxTimeStamp AccessTime;
    /// <summary>
    /// Creation time.
    /// </summary>
    internal StatxTimeStamp CreationTime;
    /// <summary>
    /// Last status change time.
    /// </summary>
    internal StatxTimeStamp StatusChangeTime;
    /// <summary>
    /// Last modification time.
    /// </summary>
    internal StatxTimeStamp LastModificationTime;
    internal uint RDevIdMajor;
    internal uint RDevIdMinor;
    internal uint DevIdMajor;
    internal uint DevIdMinor;
    internal ulong MountId;
    private ulong Padding02;
    private ulong Padding03;
    private ulong Padding04;
    private ulong Padding05;
    private ulong Padding06;
    private ulong Padding07;
    private ulong Padding08;
    private ulong Padding09;
    private ulong Padding10;
    private ulong Padding11;
    private ulong Padding12;
    private ulong Padding13;
    private ulong Padding14;
    private ulong Padding15;
}

/// <summary>
/// Time stamp structure used by statx.
/// </summary>
public struct StatxTimeStamp {

    /// <summary>
    /// Seconds since the Epoch (UNIX time).
    /// </summary>
    public long Seconds;

    /// <summary>
    /// Nanoseconds since <see cref="Seconds"/>.
    /// </summary>
    public uint Nanoseconds;

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 p/invoke 在没有 Mono.Posix 的情况下在 .NET 5 / .NET 6 中获取 Linux 文件权限? 的相关文章

  • 如何在 C# 中从 UNIX 纪元时间转换并考虑夏令时?

    我有一个从 unix 纪元时间转换为 NET DateTime 值的函数 public static DateTime FromUnixEpochTime double unixTime DateTime d new DateTime 19
  • 推导指南中的引用和值之间的差异

    考虑类型A template
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • 生成(非常)大的非重复整数序列而不进行预洗牌

    背景 我编写了一个简单的媒体客户端 服务器 我想生成一个不明显的时间值 随从客户端到服务器的每个命令一起发送 时间戳中将包含相当多的数据 纳秒分辨率 即使它不是真正准确 因为现代操作系统中计时器采样的限制 等 我想做的 在 Linux 上
  • 无法在 Windows 运行时组件库的 UserControl 中创建依赖项属性

    我想在用户控件内创建数据可绑定属性 这个用户控件包含一个 Windows 运行时组件 项目 我使用下面的代码来创建属性 public MyItem CurrentItem get return MyItem GetValue Current
  • 如何在 C# 中定义文本框数组?

    您好 当我在 Windows 申请表上创建文本框时 我无法将其命名为 box 0 box 1 等 我这样做的目的是因为我想循环使用它们 其实我发现TextBox array firstTextBox secondTextBox 也有效
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • ASP.NET:获取自 1970 年 1 月 1 日以来的毫秒数

    我有一个 ASP NET VB NET 日期 我试图获取自 1970 年 1 月 1 日以来的毫秒数 我尝试在 MSDN 中寻找方法 但找不到任何东西 有谁知道如何做到这一点 从 NET 4 6 开始 该方法ToUnixTimeMillis
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • 如何使用 watin 中的 FileUploadDialogHandler 访问文件上传对话框

    我正在使用 IE8 和 watin 并尝试通过我的网页测试上传文件 我不能简单地使用 set 方法设置上传文件 例如 ie FileUpload Find ById someId Set C Desktop image jpg 因为上传文本
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 如何在 Blackberry Cascades 中显示具有特定号码的电话板

    我正在使用带有 C QT 和 QML 的 Blackberry Cascades 10 Beta 3 SDK 以及 Blackberry 10 Dev Alpha Simulator 和 QNX Momentics IDE 并且我正在尝试实
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 将自定义 ValueProviderFactories 添加到 ASP.NET MVC3?

    我试图尝试将 Protobuf ValueProviderFactory 添加到 MVC3 以便我可以选择 MIME 类型并将原始数据反序列化为操作参数的对象 我还可以使用它来更改默认的 Json 序列化器 看着JsonValueProvi

随机推荐

  • 转储文件分析入门

    我正在使用旧版 VB6 COM 应用程序 该应用程序有时会导致 Windows 7 崩溃 我现在已经使用 Sysinternals 的 ProcDump 工具生成了其中一个崩溃的 dmp 文件 但是 我以前从未使用过转储文件 您会推荐哪些资
  • 从 ScrollView Swift 中删除子视图

    我使用 for 循环在滚动视图中创建标签和按钮 是否可以删除滚动视图内的所有对象 我想用新内容更新它 for peop in personArray scrollView clearContent Name label var label
  • 格式化 NSNumber 对象时如何指定小数位?

    我使用下面的一段 Objective C 代码来格式化 NSNumber 它在大多数情况下都工作正常 但是当 NSNumber 对象包含整数 没有小数部分 时 它并不能完全满足我的要求 UILabel label UILabel alloc
  • Python 多处理池卡住

    我正在尝试运行在网上找到的 python multiprocessing pool 模块的一些示例代码 代码是 def square x return x x if name main pool Pool processes 4 input
  • 如何区分类型是值类型还是引用类型?

    一些简单的类型 如 int string 等 很容易意识到它们是 ValueTypes 或 RefrenceTypes 但我想知道有什么方法可以区分吗 所有结构 枚举和本机类型都是值类型 在运行时你可以这样检查 Type type type
  • 如何为 HTTP GET 请求设置标头并触发文件下载?

    Update20140702 解决方案 详细答案作为博客文章 但我将其他答案之一标记为已接受 而不是我自己的 因为它让我成功了一半 并奖励我的努力 似乎无法通过以下链接设置 HTTP 请求标头 a href 并且只能使用XMLHttpReq
  • HTTP 请求在 Postman 中有效,但在 C# 代码中无效

    我想用 C 做一个简单的 HTTP 请求 但是有些东西不起作用 我得到的只是403 Forbidden状态码 当我尝试在邮递员中执行相同的请求时 一切正常 我尝试运行 Fiddler 并查看 Postman 发送的所有标头 我全部复制粘贴了
  • 我是否应该要求 IdP 签署 SAML2 SSO 响应?

    我们的应用程序具有与 3 个不同 Shibboleth IdP 的 SAML2 SSO 集成 我们正在尝试添加第四个 也是 Shibboleth 但遇到了一些问题 因为我们的应用程序期望所有 SSO 响应都经过验证签名 其他 3 个正在签署
  • 从 Nhibernate 执行的查询很慢,但从 ADO.NET 执行的查询很快

    我的 MVC 应用程序中有一个查询 大约需要 20 秒才能完成 使用 NHibernate 3 1 当我在 Management studio 上手动执行查询时 需要 0 秒 我在 SO 上看到过类似的问题 所以我进一步进行了测试 我使用
  • 是否可以为字符串文字创建模板化的用户定义文字(文字后缀)?

    当我发现可以制作用户定义的文字模板时 我感到很惊讶 template
  • 从 setTimeout 获取返回值[重复]

    这个问题在这里已经有答案了 我只想获取返回值setTimeout但我得到的是函数的完整文本格式 function x setTimeout y function return done 1000 return y console log x
  • Android - 仅将方向锁定为两个方向

    如何使我的 Android 应用程序成为横向或纵向 但没有相反的方向 意思是我想启用SCREEN ORIENTATION PORTRAIT and SCREEN ORIENTATION LANDSCAPE但要禁用SCREEN ORIENTA
  • ckeditor - onpaste 事件

    有谁知道我如何附加onpasteCKEditor 3 x 中的事件 I basically want to grab CTRL V data and add few text to it and then add it to the edi
  • 如何使用 GDB 7.x 查看 STL 容器的内容

    我一直在使用宏解决方案 正如它所概述的那样here 但是 其中提到了如何在没有宏的情况下查看它们 我指的是 GDB 7 及以上版本 有人能说明一下如何吗 Thanks 从 SVN 获取 python 查看器 svn gcc gnu org
  • 从 Objective-C 移植到 C++ 的最佳方式是什么?

    我没有任何 Objective C 经验 但有很强的 C 背景 是否有一个自动化工具 脚本 或者 最坏的情况下 是否有一些手动方法 使用一些优秀的参考来将 Objective C 编写的代码移植到 C 其中有何困难 编辑 我听说该代码相当简
  • 给搜索栏一个半圆形

    是否可以使用 android 形状元素为 Seekbar 提供弧形形状 如果没有 还有其他方法可以改变搜索栏的形状吗 我有一个允许半圆的开源 CircularSeekBar http devadvance com circularseekb
  • 平移寻找AVPlayer

    我正在尝试在 AVPlayer 中向前和向后平移和搜索 这是可行的 但确定平移在何处转换为资产长度的基本数学是错误的 有人可以提供帮助吗 void handlePanGesture UIPanGestureRecognizer pan CG
  • Flutter 的 Paragraph 类的宽度指标有何含义?

    The 文档for Paragraph 有四种不同的方法来获取宽度距离 宽度 双倍该段落占用的水平空间量 最长线 双段落中从最左边字形的左边缘到最右边字形的右边缘的距离 最大固有宽度 双精度返回最小宽度 超过该宽度增加宽度不会减小高度 mi
  • 有没有办法更快地发现BLE外设服务?

    我发现我在 iOS7 中实现 BLE 协议在启动阶段非常慢 在我的应用程序中 启动序列约占整个执行时间的 68 我该怎么做才能让它更快 我已经计时了 这就是我得到的 t dt 37 598 BLE Discovered peripheral
  • 如何使用 p/invoke 在没有 Mono.Posix 的情况下在 .NET 5 / .NET 6 中获取 Linux 文件权限?

    我最近发现 我可以相对容易地从 NET 进行 Linux 系统调用 例如 看看我是否需要sudo我只是做了这样的签名 internal class Syscall DllImport libc SetLastError true inter