Source file
src/os/root_js.go
1
2
3
4
5
6
7 package os
8
9 import (
10 "errors"
11 "slices"
12 "syscall"
13 )
14
15
16
17
18
19 func checkPathEscapes(r *Root, name string) error {
20 return checkPathEscapesInternal(r, name, false)
21 }
22
23
24
25
26
27
28 func checkPathEscapesLstat(r *Root, name string) error {
29 return checkPathEscapesInternal(r, name, true)
30 }
31
32 func checkPathEscapesInternal(r *Root, name string, lstat bool) error {
33 if r.root.closed.Load() {
34 return ErrClosed
35 }
36 parts, endsInSlash, err := splitPathInRoot(name, nil, nil)
37 if err != nil {
38 return err
39 }
40
41 i := 0
42 symlinks := 0
43 base := r.root.name
44 for i < len(parts) {
45 if parts[i] == ".." {
46
47 end := i + 1
48 for end < len(parts) && parts[end] == ".." {
49 end++
50 }
51 count := end - i
52 if count > i {
53 return errPathEscapes
54 }
55 parts = slices.Delete(parts, i-count, end)
56 i -= count
57 base = r.root.name
58 for j := range i {
59 base = joinPath(base, parts[j])
60 }
61 continue
62 }
63
64 part := parts[i]
65 if i == len(parts)-1 {
66 if lstat && !endsInSlash {
67 break
68 }
69 }
70
71 next := joinPath(base, part)
72 fi, err := Lstat(next)
73 if err != nil {
74 if IsNotExist(err) {
75 return nil
76 }
77 return underlyingError(err)
78 }
79 if fi.Mode()&ModeSymlink != 0 {
80 link, err := Readlink(next)
81 if err != nil {
82 return errPathEscapes
83 }
84 symlinks++
85 if symlinks > rootMaxSymlinks {
86 return errors.New("too many symlinks")
87 }
88 newparts, newEndsInSlash, err := splitPathInRoot(link, parts[:i], parts[i+1:])
89 if err != nil {
90 return err
91 }
92 if i == len(parts)-1 && newEndsInSlash {
93 endsInSlash = true
94 }
95 parts = newparts
96 continue
97 }
98 if !fi.IsDir() && i < len(parts)-1 {
99 return syscall.ENOTDIR
100 }
101
102 base = next
103 i++
104 }
105 return nil
106 }
107
View as plain text