递归创建具有特定所有者和组的目录

I would like to recursively create a directory and assign an owner and group for the folders and its parents that were created.

For example, assuming /var exists, I want to create /var/test1/test2/test3.

I am able to do this using os.MkdirAll("/var/test1/test2/test3", 0600).

However, I also want to set test1, test2, and test3's uid to user1 and gid to user1.

It's possible to do so using os.Chown, but that requires a lot of manually work. I would need build a tree of the folder and its parents that do not exist before creating the folder chain and then use os.Chown on each folder after creation.

Is there a simpler way?

A bit like this ChownR() type of function, the idea would be to filter the walk, and apply the chown only to folders which are part of a path passed in parameter (here "/var/test1/test2/test3)

Without filter:

func ChownR(path string, uid, gid int) error {
    return filepath.Walk(path, func(name string, info os.FileInfo, err error) error {
        if err == nil {
            err = os.Chown(name, uid, gid)
        }
        return err
    })
}

In other words, with filepath.Walk(), there should not be too much "manual work" involved here.

Switch the mkdir process to the user you wish to create directories for. This has the advantage of creating directories with correct permissions and ownership in a single command instead of creating loops or running multiple commands back to back.

Example:

import "os/exec"
import "syscall"

func main() {
    // The command here can use flags to create all of the dirs at once
    cmd := exec.Command('mkdir', '-p', '/var/test1/test2/test3/')

    _ = syscall.Umask(0077) // Set umask for this process

    cmd.SysProcAttr = &syscall.SysProcAttr{}
    cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}

    cmd.Run()

}

Since the subprocess "mkdir" runs as the user specified by uid, the folders would already have the correct owner. If you get the umask part right, each directory will also have correct permissions.

One caveat: this is not a very portable solution. Using syscall should only be your solution if you are certain your code will only be executing on a specific OS.