package fs import ( "os" "syscall" "time" "github.com/pkg/errors" ) func Chown(p string, old *User, fn Chowner) error { if fn == nil { return nil } user, err := fn(old) if err != nil { return errors.WithStack(err) } if user != nil { if err := os.Lchown(p, user.UID, user.GID); err != nil { return err } } return nil } // MkdirAll is forked os.MkdirAll func MkdirAll(path string, perm os.FileMode, user Chowner, tm *time.Time) error { // Fast path: if we can tell whether path is a directory or file, stop with success or error. dir, err := os.Stat(path) if err == nil { if dir.IsDir() { return nil } return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} } // Slow path: make sure parent exists and then call Mkdir for path. i := len(path) for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. i-- } j := i for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. j-- } if j > 1 { // Create parent. err = MkdirAll(fixRootDirectory(path[:j-1]), perm, user, tm) if err != nil { return err } } dir, err1 := os.Lstat(path) if err1 == nil && dir.IsDir() { return nil } // Parent now exists; invoke Mkdir and use its result. err = os.Mkdir(path, perm) if err != nil { // Handle arguments like "foo/." by // double-checking that directory doesn't exist. dir, err1 := os.Lstat(path) if err1 == nil && dir.IsDir() { return nil } return err } if err := Chown(path, nil, user); err != nil { return err } if err := Utimes(path, tm); err != nil { return err } return nil }