Search code examples
c#linuxfilepermissions

Service to write files with specific group and permissions C#


I am writing a program, intending to run it using the daemon/service/no-login user aaa. User aaa is part of group shareabc and sharedef. The configuration file for this program will look like:

{
   ... other config ...
   "locations": [
      {
         "id": "workflow1",
         "location": "/shr/abc",
         "group": "shareabc"
      },
      {
         "id": "workflow2",
         "location": "/shr/def",
         "group": "sharedef"
      },
   ],
   ... other config ...
}
  • /shr/abc belongs to root:shareabc
  • /shr/def belongs to root:sharedef

If, in my program, I call Directory.CreateDirectory("/shr/abc/myfolder1");, then /shr/abc/myfolder1 will be created with the owner aaa:aaa.

What C# code do I need to make it create the folder with the owner aaa:shareabc instead of aaa:aaa?

Running the program as user aaa group shareabc isn't a solution, as:

  1. There are some files which should be aaa:aaa, and there are others which should be aaa:shareabc. Changing the running user/group, or changing filesystem defaults, just shifts the problem rather than solving it.
  2. I would run into the same problem when it tries to write to folder /shr/def using owner aaa:sharedef.

As for setting the permissions, it seems they've updated the C# API a few years ago. I can just call the following to create it with 775: Directory.CreateDirectory("/shr/abc/myfolder1", UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.GroupExecute | UnixFileMode.OtherRead | UnixFileMode.OtherExecute);


Solution

  • Since there are no permission issues, you can directly run the chown command.

    Process.Start("chown", $"aaa:shareabc {directoryPath}").WaitForExit();
    

    If you prefer a C# method, there are several packages Mono.Posix.NETStandard, Mono.Posix, Mono.Unix that do the work.

    using Mono.Unix;
    UnixFileSystemInfo.GetFileSystemEntry(directoryPath)
                      .SetOwner("abc", "shareabc");
    

    This method actually calls the chown function of libc, so you can also do:

    [DllImport("libc", SetLastError = true)]
    static extern int chown(string path, int owner, int group);
    
    chown(directoryPath, -1, group_id_of_shareabc);