代码之家  ›  专栏  ›  技术社区  ›  Stefan Steiger

如何在C#中映射双C结构节点?

  •  0
  • Stefan Steiger  · 技术社区  · 4 年前

    我对libACL进行了以下C调用:

    extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
    extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
    

    我追踪了这些字体

    typedef struct __acl_permset_ext *acl_permset_t;
    typedef struct __acl_entry_ext  *acl_entry_t;
    typedef struct __acl_ext *acl_t;
    

    在/usr/include/acl/libacl.h和/usr/inclute/sys/acl中。h

    因此,除非我犯了错误,否则这意味着上述本机调用等效于:

    extern int acl_get_entry(__acl_ext *acl, int entry_id, __acl_entry_ext **entry_p);
    extern int acl_get_permset(__acl_ext *entry_d, __acl_permset_ext **permset_p);
    

    现在我有点不知道如何将这些映射到C#。。。
    我起初以为我可以这样做:

    // extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
    [SuppressUnmanagedCodeSecurity]
    [DllImport("acl", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint = "acl_get_entry")]
    internal static extern int acl_get_entry(__acl_ext* acl, AclEntryConstants entry_id, ref __acl_entry_ext entry_p); // Double pointer, correct ???
    

    这甚至奏效了,至少表面上是这样。
    但当我对acl_get_permset做同样的事情时

    // extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
    [SuppressUnmanagedCodeSecurity]
    [DllImport("acl", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl,
       EntryPoint = "acl_get_permset")]
    internal static extern int acl_get_permset(__acl_entry_ext* entry_d, __acl_permset_ext** permset_p); // double pointer ?
    

    又称作

    internal static extern int acl_get_permset(__acl_entry_ext* entry_d, ref __acl_permset_ext permset_p); // double pointer ?
    

    那么它就不起作用了。。。

    我编写了以下C代码进行检查:

    int main()
    {
       // Get all the entries
       acl_entry_t acl_entry_;
       acl_permset_t permission_set;
       acl_tag_t acl_kind_tag;
    
       const char* _filename = "/root/Desktop/CppSharp.txt";
       acl_t acl_file = acl_get_file(_filename, ACL_TYPE_ACCESS);
       int found = acl_get_entry(acl_file, ACL_FIRST_ENTRY, &acl_entry_);
    
    
       int a = acl_get_permset(acl_entry_, &permission_set);
       int b = acl_get_tag_type(acl_entry_, &acl_kind_tag);
       printf("a: %d; b: %d\n", a, b);
    
       acl_entry new_acl;
       new_acl.reading = ACL_GET_PERM(permission_set, ACL_READ);
       new_acl.writing = ACL_GET_PERM(permission_set, ACL_WRITE);
       new_acl.execution = ACL_GET_PERM(permission_set, ACL_EXECUTE);
    
    
       return 0;
    }
    

    并且它为a和b返回一个非1的值。
    但是我的C#代码,它的功能完全相同(或者我想是这样) int found = 1 (就像C一样),但对于a和b,它返回-1。。。

    static unsafe void ReadACL()
    {
       string fileName = "/root/Desktop/CppSharp.txt";
      
       global::acl.__acl_ext* acl_file = NativeMethods.acl_get_file(fileName, global::acl.acl_type_t.ACL_TYPE_ACCESS);
    
    
       global::acl.__acl_entry_ext acl_entry_ = new global::acl.__acl_entry_ext();
       int found = NativeMethods.acl_get_entry(acl_file, global::acl.AclEntryConstants.ACL_FIRST_ENTRY, ref acl_entry_);
       System.Console.WriteLine(found);
    
    
       global::acl.__acl_permset_ext permission_set;
       acl_tag_t acl_kind_tag = acl_tag_t.ACL_UNDEFINED_TAG;
      
      
       int a = NativeMethods.acl_get_permset(&acl_entry_, &permission_set);
       global::acl.acl_tag_t tag_type = acl_tag_t.ACL_UNDEFINED_TAG;
       int b = NativeMethods.acl_get_tag_type(&acl_entry_, &tag_type);
    
       System.Console.WriteLine($"{a} {b}");
    

    此外,最奇怪的是,我搜索了以下头文件:

    /usr/include/acl/libacl.h 
    /usr/include/sys/acl.h
    

    以及整个 /usr/include 文件夹 __acl_permset_ext __acl_entry_ext ,但我需要用谷歌搜索它们,因为它们没有明确的定义。。。C编译器是否只使用指针,而根本不需要结构?

    此外,在手动操作之前,我曾尝试使用CppSharp自动创建绑定,但这些自动生成的绑定也有同样的问题。。。

    mono ./CppSharp.CLI.exe --arch=x64 --output=/home/username/RiderProjects/TestProject/TestProject/AUTOMAPPED/  /usr/include/acl/libacl.h /usr/include/sys/acl.h
    

    还有一件事我注意到了: 传递双指针有什么意义? 这就像

    struct x;
    function(ref &x)
    

    在我看来,这没有什么意义,因为你是通过引用传递地址的。
    这些可能是数组吗?
    喜欢

    struct[] x;
    function(ref x)
    

    以下是常数:

    // #define ACL_UNDEFINED_ID    ((id_t)-1)
    
    // acl_check error codes
    public enum acl_check_errors
       : int
    {
        ACL_MULTI_ERROR = (0x1000), // multiple unique objects
        ACL_DUPLICATE_ERROR = (0x2000), // duplicate Id's in entries
        ACL_MISS_ERROR = (0x3000), // missing required entry
        ACL_ENTRY_ERROR = (0x4000) // wrong entry type 
    }
    
    
    // 23.2.2 acl_perm_t values
    public enum acl_perm_t
       : uint
    {
       ACL_READ = (0x04),
       ACL_WRITE = (0x02),
       ACL_EXECUTE = (0x01),
       // ACL_ADD = (0x08),
       // ACL_DELETE = (0x10),
    }
    
    
    // 23.2.5 acl_tag_t values
    public enum acl_tag_t
       : int
    {
       ACL_UNDEFINED_TAG = (0x00),
       ACL_USER_OBJ = (0x01),
       ACL_USER = (0x02),
       ACL_GROUP_OBJ = (0x04),
       ACL_GROUP = (0x08),
       ACL_MASK = (0x10),
       ACL_OTHER = (0x20)
    }
    
    public enum acl_type_t
       : uint
    {
       ACL_TYPE_ACCESS = (0x8000),
       ACL_TYPE_DEFAULT = (0x4000)
    }   
    // 23.2.8 ACL Entry Constants
    public enum AclEntryConstants
       : int
    {
       ACL_FIRST_ENTRY = 0,
       ACL_NEXT_ENTRY = 1,
    }
    

    这是我在谷歌上搜索到的结构:

    // https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libobj.h
    // https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libobj.h
    // https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libacl.h
    // https://allstar.jhuapl.edu/repo/p1/amd64/acl/libacl.h
    // https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/libacl.h
    // https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/301faaf37f99fc30105f261f23d44e2a0632ffc0/acl/libacl/acl_get_fd.c
    
    
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct obj_prefix
    {
       public ulong p_magic;
       public ulong p_flags;
    }
    
    // typedef struct __acl_permset_ext *acl_permset_t;
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct __acl_permset_ext
    {
       // permset_t      s_perm; // typedef unsigned int permset_t;
       public uint s_perm;
    };
    
    // typedef struct acl_permset_obj_tag acl_permset_obj;
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct acl_permset_obj_tag
    {
       public obj_prefix o_prefix;
       public __acl_permset_ext i;
    };
    
    // #define __U32_TYPE     unsigned int
    // #define __ID_T_TYPE    __U32_TYPE
    // __STD_TYPE __ID_T_TYPE __id_t;     /* General type for IDs.  */
    // typedef __id_t id_t;
    
    /* qualifier object */
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct __qualifier_ext
    {
       //id_t                    q_id;
       public uint q_id;
    }
    
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct qualifier_obj_tag
    {
       public obj_prefix o_prefix;
       public __qualifier_ext i;
    }
    
    
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct acl_entry_obj_tag
    {
       public obj_prefix o_prefix;
       public __acl_entry_ext i;
    }
    
    
    // typedef struct __acl_ext    *acl_t;
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct __acl_ext
    {
       // typedef struct acl_entry_obj_tag acl_entry_obj;
       // acl_entry_obj      *a_prev, *a_next;
       // acl_entry_obj      *a_curr;
       // acl_entry_obj      *a_prealloc, *a_prealloc_end;
    
       public acl_entry_obj_tag* a_prev;
       public acl_entry_obj_tag* a_next;
       public acl_entry_obj_tag* a_curr;
       public acl_entry_obj_tag* a_prealloc;
    
       public acl_entry_obj_tag* a_prealloc_end;
    
       // size_t a_used; // typedef __SIZE_TYPE__ size_t;
       public ulong a_used;
    }
    
    
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct acl_obj_tag
    {
       public obj_prefix o_prefix;
       public __acl_ext i;
    }
    
    
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct __acl_entry
    {
       acl_tag_t e_tag;
    
       // qualifier_obj      e_id; // typedef struct qualifier_obj_tag qualifier_obj;
       qualifier_obj_tag e_id;
    
       // acl_permset_obj    e_perm;  //typedef struct acl_permset_obj_tag acl_permset_obj;
       acl_permset_obj_tag e_perm;
    }
    
    
    // typedef struct __acl_entry_ext  *acl_entry_t;
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public unsafe struct __acl_entry_ext
    {
       // acl_entry_obj      *e_prev, *e_next; // typedef struct acl_entry_obj_tag acl_entry_obj;
       public acl_entry_obj_tag* e_prev;
    
       public acl_entry_obj_tag* e_next;
    
       // acl_obj       *e_container; // typedef struct acl_obj_tag acl_obj;
       public acl_obj_tag* e_container;
       public __acl_entry e_entry;
    }
    
    0 回复  |  直到 4 年前
        1
  •  1
  •   canton7    4 年前

    从看 here ,这些ACL类型定义为:

    struct __acl_ext;
    struct __acl_entry_ext;
    struct __acl_permset_ext;
    
    typedef struct __acl_ext    *acl_t;
    typedef struct __acl_entry_ext  *acl_entry_t;
    typedef struct __acl_permset_ext *acl_permset_t;
    

    我们被告知,结构 __acl_ext 存在,但我们无法看到它是如何定义的:我们不知道它有哪些字段。显然,它在另一个(私有)头文件或源文件中得到了正确的定义,但我们无法看到它们:它们是私有的。

    从表面上看,这似乎是一个问题:如果我们不知道这些结构有多大,或者它们的字段是如何布局的,我们怎么能使用它们呢?再往前看,你可以看到我们只与 指针 对于这些结构:ACL函数将返回一个指针,然后我们可以将其传递给其他ACL函数。我们永远不会自己去引用指针。ACL代码当然知道指针指向什么,但这对我们来说是隐藏的。

    这被称为 opaque pointer .

    (这可能是一个有用的策略。例如,它允许ACL库在不破坏消费者的情况下更改结构的定义方式。它还阻止我们直接更改这些结构中的字段,这可能会破坏ACL库)。

    所以,我们根本不应该为这些结构定义C#类型:我们根本不打算这样做。不透明指针的C#类型为 IntPtr ,所以让我们使用它:

    // extern int acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p);
    [SuppressUnmanagedCodeSecurity]
    [DllImport("acl", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acl_get_entry")]
    internal static extern int acl_get_entry(IntPtr acl, AclEntryConstants entry_id, out IntPtr entry_p);
    
    // extern int acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p);
    [SuppressUnmanagedCodeSecurity]
    [DllImport("acl", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acl_get_permset")]
    internal static extern int acl_get_permset(IntPtr entry_d, out IntPtr permset_p);
    

    我们可以用 ref out 对于 IntPtr 在阅读文档时,C代码似乎从不读取您传入的双指针的值:它只是将其用作将指针传递回的一种方式。因此,我们使用 外面的 .