@@ -2,6 +2,8 @@ package jailer
22
33import (
44 "os"
5+ "path/filepath"
6+ "syscall"
57
68 "golang.org/x/sys/unix"
79)
@@ -20,25 +22,71 @@ func mkdirAndChown(path string, uid, gid int, perm os.FileMode) error {
2022 return nil
2123}
2224
23- func mkdirAllAndChown (path string , uid , gid int , perm os. FileMode ) error {
24- err := os . MkdirAll (path , perm )
25+ func mkFifo (path string , uid , gid int , mode uint32 ) error {
26+ err := unix . Mkfifo (path , mode )
2527 if err != nil {
2628 return err
2729 }
2830
29- err = os .Chown (path , uid , gid )
31+ return os .Chown (path , uid , gid )
32+ }
33+
34+ // Copyright 2017 The Go Authors. All rights reserved.
35+ // Use of this source code is governed by a BSD-style
36+ // license that can be found in the https://cs.opensource.google/go/go LICENSE file.
37+ //
38+ // Extracted from os.MkdirAll
39+ func mkdirAllAndChown (path string , perm os.FileMode , uid , gid int ) error {
40+ // Fast path: if we can tell whether path is a directory or file, stop with success or error.
41+ dir , err := os .Stat (path )
42+ if err == nil {
43+ if dir .IsDir () {
44+ return nil
45+ }
46+ return & os.PathError {Op : "mkdir" , Path : path , Err : syscall .ENOTDIR }
47+ }
48+
49+ // Slow path: make sure parent exists and then call Mkdir for path.
50+
51+ // Extract the parent folder from path by first removing any trailing
52+ // path separator and then scanning backward until finding a path
53+ // separator or reaching the beginning of the string.
54+ i := len (path ) - 1
55+ for i >= 0 && os .IsPathSeparator (path [i ]) {
56+ i --
57+ }
58+ for i >= 0 && ! os .IsPathSeparator (path [i ]) {
59+ i --
60+ }
61+ if i < 0 {
62+ i = 0
63+ }
64+
65+ // If there is a parent directory, and it is not the volume name,
66+ // recurse to ensure parent directory exists.
67+ if parent := path [:i ]; len (parent ) > len (filepath .VolumeName (path )) {
68+ err = mkdirAllAndChown (parent , perm , uid , gid )
69+ if err != nil {
70+ return err
71+ }
72+ }
73+
74+ // Parent now exists; invoke Mkdir and use its result.
75+ err = os .Mkdir (path , perm )
3076 if err != nil {
77+ // Handle arguments like "foo/." by
78+ // double-checking that directory doesn't exist.
79+ dir , err1 := os .Lstat (path )
80+ if err1 == nil && dir .IsDir () {
81+ return nil
82+ }
3183 return err
3284 }
3385
34- return nil
35- }
36-
37- func mkFifo (path string , uid , gid int , mode uint32 ) error {
38- err := unix .Mkfifo (path , mode )
86+ err = os .Chown (path , uid , gid )
3987 if err != nil {
4088 return err
4189 }
4290
43- return os . Chown ( path , uid , gid )
91+ return nil
4492}
0 commit comments