mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
de56a90929
Signed-off-by: Tibor Vass <tibor@docker.com>
83 lines
1.6 KiB
Go
83 lines
1.6 KiB
Go
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
|
|
}
|