首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用p/invoke在Linux上获取UID和GID?

如何使用p/invoke在Linux上获取UID和GID?
EN

Stack Overflow用户
提问于 2021-10-28 08:29:06
回答 1查看 304关注 0票数 3

对于服务安装程序,我需要Linux机器上的一些简单的文件操作。代码是.NET 5.0。

我的当前版本使用Process.Start()执行shell命令,以更改文件和目录的所有者并设置权限。

这是相当慢的(我使用异步方法),特别是与Windows等效的方法相比。

我看到libc可以从.NET调用chmodchown方法,但是它需要uidgid参数。我的应用程序不知道it,至少不使用shell。

到目前为止,我得到了这样的东西:

代码语言:javascript
运行
复制
const string LIBC = "libc";

[DllImport(LIBC, SetLastError = true)]
private static extern int chmod(string path, uint mode);

[DllImport(LIBC, SetLastError = true)]
private static extern int chown(string path, int owner, int group);

所以..。如何获得所需的两个ints?

更新

为什么有人认为这个问题(特别是考虑到它的标题)重复问题的相似,但不同的东西。

我知道如何以多种方式更改Linux文件的所有者和权限。最简单的方法是使用Linux。最快也是最简单的方法是使用Mono.Posix.NETStandard库,在内部调用libc

我的具体问题是它是如何制作的?它怎麽工作?

更具体的是:下面是getpwnam()https://man7.org/linux/man-pages/man3/getpwnam.3.html的Linux手册页面

如何使用p/invoke从C#调用?我在许多例子中看到,当他们用char*代替string时,它神奇地起了作用。我创建了这样一个结构:

代码语言:javascript
运行
复制
public struct PASSWD {
    public string pw_name;       /* username */
    public string pw_passwd;     /* user password */
    public int pw_uid;        /* user ID */
    public int pw_gid;        /* group ID */
    public string pw_gecos;      /* user information */
    public string pw_dir;        /* home directory */
    public string pw_shell;      /* shell program */
};

...and试图使用它作为签名的out参数。我没有错误,但它就是不起作用。我得到的结构是空的。

因此,我们再次使用平台调用,在C#中,我们调用libc,我们希望从结构中获得结果。据我搜索-这是不能谷歌的。只有Mono源代码,它使用外部模块来实现我所需要的。我怀疑他们之所以这么做是因为性能方面的原因,也是因为他们使用了一些特殊的工具,因为在注释中,代码是生成的。

我的问题是,如何使用Linux手动页面定义为C#创建适当的方法签名,以便能够从getpwnam()中提取这两个整数。

我也很好奇,这样的东西是否已经存在于.NET本身,但我想它并不存在。

EN

Stack Overflow用户

回答已采纳

发布于 2021-10-31 05:36:59

所以,我对p/invoke生疏了。我的问题是我忘记了,当本机函数返回指向结构的指针时,没有自动转换,必须保留指针的签名,因此:

代码语言:javascript
运行
复制
[DllImport(LIBC, SetLastError = true)]
internal static extern IntPtr getgrnam(string name);

[DllImport(LIBC, SetLastError = true)]
internal static extern IntPtr getpwnam(string name);

internal struct Group {

    public string Name;
    public string Password;
    public uint Gid;
    public IntPtr Members;

}

internal struct Passwd {

    public string Name;
    public string Password;
    public uint Uid;
    public uint Gid;
    public string GECOS;
    public string Directory;
    public string Shell;

}

让我们创建完全托管的.NET样式类型:

代码语言:javascript
运行
复制
public sealed class GroupInfo {

    public string Name { get; }
    public uint Id { get; }
    public string[] Members { get; }

    internal GroupInfo(Syscall.Group group) {
        Name = group.Name;
        Id = group.Gid;
        Members = GetMembers(group.Members).ToArray();
    }

    private static IEnumerable<string> GetMembers(IntPtr members) {
        IntPtr p;
        for (int i = 0; (p = Marshal.ReadIntPtr(members, i * IntPtr.Size)) != IntPtr.Zero; i++)
            yield return Marshal.PtrToStringAnsi(p)!;
    }

}

public class UserInfo {

    public string Name { get; }
    public uint Uid { get; }
    public uint Gid { get; }
    public string? Directory { get; }
    public string? Shell { get; }

    internal UserInfo(Syscall.Passwd passwd) {
        Name = passwd.Name;
        Uid = passwd.Uid;
        Gid = passwd.Gid;
        Directory = passwd.Directory;
        Shell = passwd.Shell;
    }

}

它可以这样使用:

代码语言:javascript
运行
复制
public static UserInfo? GetUserInfo(string name) {
    var result = Syscall.getpwnam(name);
    if (result != IntPtr.Zero) return new UserInfo(Marshal.PtrToStructure<Syscall.Passwd>(result));
    return null;
}

public static GroupInfo? GetGroupInfo(string name) {
    var result = Syscall.getgrnam(name);
    if (result != IntPtr.Zero) return new GroupInfo(Marshal.PtrToStructure<Syscall.Group>(result));
    return null;
}
票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69750698

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档