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