Search code examples
c#unixxattr

C# xattr file attributes


I'm creating a cross-platform software and I want to know if there is any (easy) way to read/write Unix (Mac OSX/Linux) extended file attributes in C#. I've just read about xattr namespaces, but I haven't found any information about C# implementation or bindings of this feature.

P.S. The only thing I found so far is python-xattr library, but I don't want to use it because:

  • I don't want to obligate the users to install Python (there is already Mono/.NET dependency to deal with)
  • By using Python I will have a performance decrease (C# is compiled, while Python is interpreted)
  • I don't want to rely/depend on external tools (if it's possible), because it's not safe

Solution

  • You should use the syscalls in Mono.Unix.Native.Syscall.*attr*.
    The nuget assembly is called Mono.Posix.NETStandard

    Note that the name of the name-value pair is prefixed with a namespace.
    According to man 7 xattr

    Currently, the security, system, trusted, and user extended attribute classes are defined as described below. Additional classes may be added in the future.

    public static void Test()
    {
        string path = "/root/Desktop/CppSharp.txt";
    
        // Mono.Unix.Native.Syscall.getxattr()
        // Mono.Unix.Native.Syscall.fgetxattr()
        // Mono.Unix.Native.Syscall.lgetxattr()
    
        // Mono.Unix.Native.Syscall.setxattr()
        // Mono.Unix.Native.Syscall.fsetxattr()
        // Mono.Unix.Native.Syscall.lsetxattr
    
        // Mono.Unix.Native.Syscall.llistxattr()
        // Mono.Unix.Native.Syscall.flistxattr()
        // Mono.Unix.Native.Syscall.llistxattr()
    
        // Mono.Unix.Native.Syscall.removexattr()
        // Mono.Unix.Native.Syscall.fremovexattr()
        // Mono.Unix.Native.Syscall.lremovexattr()
    
        if (System.IO.File.Exists(path))
            System.Console.WriteLine("path exists");
        else
            System.Console.WriteLine("path doesn't exists");
    
        System.Text.Encoding enc = new System.Text.UTF8Encoding(false);
        string[] values = null;
    
        int setXattrSucceeded = Mono.Unix.Native.Syscall.setxattr(path, "user.foobar",
            enc.GetBytes("Hello World äöüÄÖÜ"), Mono.Unix.Native.XattrFlags.XATTR_CREATE);
    
        if (setXattrSucceeded == -1)
        {
            Mono.Unix.Native.Errno er = Mono.Unix.Native.Stdlib.GetLastError();
            string message = Mono.Unix.Native.Stdlib.strerror(er);
            // https://stackoverflow.com/questions/12662765/how-can-i-get-error-message-for-errno-value-c-language
            System.Console.WriteLine(message);
        } // End if (setXattrSucceeded == -1)
    
        byte[] data = null;
        long szLen = Mono.Unix.Native.Syscall.getxattr(path, "user.foobar", out data);
    
        string value = enc.GetString(data);
        System.Console.WriteLine(value);
    
        Mono.Unix.Native.Syscall.listxattr(path, System.Text.Encoding.UTF8, out values);
        System.Console.WriteLine(values);
    
        // https://man7.org/linux/man-pages/man2/getxattr.2.html
    } // End Sub TestExtendedAttributes