Source file
src/os/root_noopenat.go
1
2
3
4
5
6
7 package os
8
9 import (
10 "errors"
11 "internal/filepathlite"
12 "internal/stringslite"
13 "sync/atomic"
14 "syscall"
15 "time"
16 )
17
18
19
20 type root struct {
21 name string
22 closed atomic.Bool
23 }
24
25
26 func openRootNolog(name string) (*Root, error) {
27 r, err := newRoot(name)
28 if err != nil {
29 return nil, &PathError{Op: "open", Path: name, Err: err}
30 }
31 return r, nil
32 }
33
34
35 func openRootInRoot(r *Root, name string) (*Root, error) {
36 if err := checkPathEscapes(r, name); err != nil {
37 return nil, &PathError{Op: "openat", Path: name, Err: err}
38 }
39 r, err := newRoot(joinPath(r.root.name, name))
40 if err != nil {
41 return nil, &PathError{Op: "openat", Path: name, Err: err}
42 }
43 return r, nil
44 }
45
46
47
48 func newRoot(name string) (*Root, error) {
49 fi, err := Stat(name)
50 if err != nil {
51 return nil, err.(*PathError).Err
52 }
53 if !fi.IsDir() {
54 return nil, errors.New("not a directory")
55 }
56 return &Root{&root{name: name}}, nil
57 }
58
59 func (r *root) Close() error {
60
61
62 r.closed.Store(true)
63 return nil
64 }
65
66 func (r *root) Name() string {
67 return r.name
68 }
69
70
71 func rootOpenFileNolog(r *Root, name string, flag int, perm FileMode) (*File, error) {
72 if err := checkPathEscapes(r, name); err != nil {
73 return nil, &PathError{Op: "openat", Path: name, Err: err}
74 }
75 f, err := openFileNolog(joinPath(r.root.name, name), flag, perm)
76 if err != nil {
77 return nil, &PathError{Op: "openat", Path: name, Err: underlyingError(err)}
78 }
79 return f, nil
80 }
81
82 func rootStat(r *Root, name string, lstat bool) (FileInfo, error) {
83 var fi FileInfo
84 var err error
85 if lstat {
86 err = checkPathEscapesLstat(r, name)
87 if err == nil {
88 fi, err = Lstat(joinPath(r.root.name, name))
89 }
90 } else {
91 err = checkPathEscapes(r, name)
92 if err == nil {
93 fi, err = Stat(joinPath(r.root.name, name))
94 }
95 }
96 if err != nil {
97 return nil, &PathError{Op: "statat", Path: name, Err: underlyingError(err)}
98 }
99 return fi, nil
100 }
101
102 func rootChmod(r *Root, name string, mode FileMode) error {
103 if err := checkPathEscapes(r, name); err != nil {
104 return &PathError{Op: "chmodat", Path: name, Err: err}
105 }
106 if err := Chmod(joinPath(r.root.name, name), mode); err != nil {
107 return &PathError{Op: "chmodat", Path: name, Err: underlyingError(err)}
108 }
109 return nil
110 }
111
112 func rootChown(r *Root, name string, uid, gid int) error {
113 if err := checkPathEscapes(r, name); err != nil {
114 return &PathError{Op: "chownat", Path: name, Err: err}
115 }
116 if err := Chown(joinPath(r.root.name, name), uid, gid); err != nil {
117 return &PathError{Op: "chownat", Path: name, Err: underlyingError(err)}
118 }
119 return nil
120 }
121
122 func rootLchown(r *Root, name string, uid, gid int) error {
123 if err := checkPathEscapesLstat(r, name); err != nil {
124 return &PathError{Op: "lchownat", Path: name, Err: err}
125 }
126 if err := Lchown(joinPath(r.root.name, name), uid, gid); err != nil {
127 return &PathError{Op: "lchownat", Path: name, Err: underlyingError(err)}
128 }
129 return nil
130 }
131
132 func rootChtimes(r *Root, name string, atime time.Time, mtime time.Time) error {
133 if err := checkPathEscapes(r, name); err != nil {
134 return &PathError{Op: "chtimesat", Path: name, Err: err}
135 }
136 if err := Chtimes(joinPath(r.root.name, name), atime, mtime); err != nil {
137 return &PathError{Op: "chtimesat", Path: name, Err: underlyingError(err)}
138 }
139 return nil
140 }
141
142 func rootMkdir(r *Root, name string, perm FileMode) error {
143 if err := checkPathEscapes(r, name); err != nil {
144 return &PathError{Op: "mkdirat", Path: name, Err: err}
145 }
146 if err := Mkdir(joinPath(r.root.name, name), perm); err != nil {
147 return &PathError{Op: "mkdirat", Path: name, Err: underlyingError(err)}
148 }
149 return nil
150 }
151
152 func rootMkdirAll(r *Root, name string, perm FileMode) error {
153
154
155
156
157
158 if err := checkPathEscapes(r, name); err == errPathEscapes {
159 return &PathError{Op: "mkdirat", Path: name, Err: err}
160 }
161 prefix := r.root.name + string(PathSeparator)
162 if err := MkdirAll(prefix+name, perm); err != nil {
163 if pe, ok := err.(*PathError); ok {
164 pe.Op = "mkdirat"
165 pe.Path = stringslite.TrimPrefix(pe.Path, prefix)
166 return pe
167 }
168 return &PathError{Op: "mkdirat", Path: name, Err: underlyingError(err)}
169 }
170 return nil
171 }
172
173 func rootRemove(r *Root, name string) error {
174 if err := checkPathEscapesLstat(r, name); err != nil {
175 return &PathError{Op: "removeat", Path: name, Err: err}
176 }
177 if endsWithDot(name) {
178
179 if filepathlite.Clean(name) == "." {
180 return &PathError{Op: "removeat", Path: name, Err: errPathEscapes}
181 }
182 }
183 if err := Remove(joinPath(r.root.name, name)); err != nil {
184 return &PathError{Op: "removeat", Path: name, Err: underlyingError(err)}
185 }
186 return nil
187 }
188
189 func rootRemoveAll(r *Root, name string) error {
190 if endsWithDot(name) {
191
192 return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
193 }
194 if err := checkPathEscapesLstat(r, name); err != nil {
195 if err == syscall.ENOTDIR {
196
197
198 return nil
199 }
200 return &PathError{Op: "RemoveAll", Path: name, Err: err}
201 }
202 if err := RemoveAll(joinPath(r.root.name, name)); err != nil {
203 return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
204 }
205 return nil
206 }
207
208 func rootReadlink(r *Root, name string) (string, error) {
209 if err := checkPathEscapesLstat(r, name); err != nil {
210 return "", &PathError{Op: "readlinkat", Path: name, Err: err}
211 }
212 name, err := Readlink(joinPath(r.root.name, name))
213 if err != nil {
214 return "", &PathError{Op: "readlinkat", Path: name, Err: underlyingError(err)}
215 }
216 return name, nil
217 }
218
219 func rootRename(r *Root, oldname, newname string) error {
220 if err := checkPathEscapesLstat(r, oldname); err != nil {
221 return &PathError{Op: "renameat", Path: oldname, Err: err}
222 }
223 if err := checkPathEscapesLstat(r, newname); err != nil {
224 return &PathError{Op: "renameat", Path: newname, Err: err}
225 }
226 err := Rename(joinPath(r.root.name, oldname), joinPath(r.root.name, newname))
227 if err != nil {
228 return &LinkError{"renameat", oldname, newname, underlyingError(err)}
229 }
230 return nil
231 }
232
233 func rootLink(r *Root, oldname, newname string) error {
234 if err := checkPathEscapesLstat(r, oldname); err != nil {
235 return &PathError{Op: "linkat", Path: oldname, Err: err}
236 }
237 fullOldName := joinPath(r.root.name, oldname)
238 if fs, err := Lstat(fullOldName); err == nil && fs.Mode()&ModeSymlink != 0 {
239 return &PathError{Op: "linkat", Path: oldname, Err: errors.New("cannot create a hard link to a symlink")}
240 }
241 if err := checkPathEscapesLstat(r, newname); err != nil {
242 return &PathError{Op: "linkat", Path: newname, Err: err}
243 }
244 err := Link(fullOldName, joinPath(r.root.name, newname))
245 if err != nil {
246 return &LinkError{"linkat", oldname, newname, underlyingError(err)}
247 }
248 return nil
249 }
250
251 func rootSymlink(r *Root, oldname, newname string) error {
252 if err := checkPathEscapesLstat(r, newname); err != nil {
253 return &PathError{Op: "symlinkat", Path: newname, Err: err}
254 }
255 err := Symlink(oldname, joinPath(r.root.name, newname))
256 if err != nil {
257 return &LinkError{"symlinkat", oldname, newname, underlyingError(err)}
258 }
259 return nil
260 }
261
View as plain text