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, 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 if lstat && i == len(parts)-1 {
65 break
66 }
67
68 next := joinPath(base, parts[i])
69 fi, err := Lstat(next)
70 if err != nil {
71 if IsNotExist(err) {
72 return nil
73 }
74 return underlyingError(err)
75 }
76 if fi.Mode()&ModeSymlink != 0 {
77 link, err := Readlink(next)
78 if err != nil {
79 return errPathEscapes
80 }
81 symlinks++
82 if symlinks > rootMaxSymlinks {
83 return errors.New("too many symlinks")
84 }
85 newparts, err := splitPathInRoot(link, parts[:i], parts[i+1:])
86 if err != nil {
87 return err
88 }
89 parts = newparts
90 continue
91 }
92 if !fi.IsDir() && i < len(parts)-1 {
93 return syscall.ENOTDIR
94 }
95
96 base = next
97 i++
98 }
99 return nil
100 }
101
View as plain text