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 name == "" {
147 return &PathError{Op: "mkdirat", Path: name, Err: syscall.ENOENT}
148 }
149 if err := Mkdir(joinPath(r.root.name, name), perm); err != nil {
150 return &PathError{Op: "mkdirat", Path: name, Err: underlyingError(err)}
151 }
152 return nil
153 }
154
155 func rootMkdirAll(r *Root, name string, perm FileMode) error {
156
157
158
159
160
161 if err := checkPathEscapes(r, name); err == errPathEscapes {
162 return &PathError{Op: "mkdirat", Path: name, Err: err}
163 }
164 if name == "" {
165 return &PathError{Op: "mkdirat", Path: name, Err: syscall.ENOENT}
166 }
167 prefix := r.root.name + string(PathSeparator)
168 if err := MkdirAll(prefix+name, perm); err != nil {
169 if pe, ok := err.(*PathError); ok {
170 pe.Op = "mkdirat"
171 pe.Path = stringslite.TrimPrefix(pe.Path, prefix)
172 return pe
173 }
174 return &PathError{Op: "mkdirat", Path: name, Err: underlyingError(err)}
175 }
176 return nil
177 }
178
179 func rootRemove(r *Root, name string) error {
180 if err := checkPathEscapesLstat(r, name); err != nil {
181 return &PathError{Op: "removeat", Path: name, Err: err}
182 }
183 if endsWithDot(name) {
184
185 if filepathlite.Clean(name) == "." {
186 return &PathError{Op: "removeat", Path: name, Err: errPathEscapes}
187 }
188 }
189 if err := Remove(joinPath(r.root.name, name)); err != nil {
190 return &PathError{Op: "removeat", Path: name, Err: underlyingError(err)}
191 }
192 return nil
193 }
194
195 func rootRemoveAll(r *Root, name string) error {
196
197
198 for len(name) > 0 && IsPathSeparator(name[len(name)-1]) {
199 name = name[:len(name)-1]
200 }
201 if endsWithDot(name) {
202
203 return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
204 }
205 if err := checkPathEscapesLstat(r, name); err != nil {
206 if err == syscall.ENOTDIR {
207
208
209 return nil
210 }
211 return &PathError{Op: "RemoveAll", Path: name, Err: err}
212 }
213 if err := RemoveAll(joinPath(r.root.name, name)); err != nil {
214 return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
215 }
216 return nil
217 }
218
219 func rootReadlink(r *Root, name string) (string, error) {
220 if err := checkPathEscapesLstat(r, name); err != nil {
221 return "", &PathError{Op: "readlinkat", Path: name, Err: err}
222 }
223 name, err := Readlink(joinPath(r.root.name, name))
224 if err != nil {
225 return "", &PathError{Op: "readlinkat", Path: name, Err: underlyingError(err)}
226 }
227 return name, nil
228 }
229
230 func rootRename(r *Root, oldname, newname string) error {
231 if err := checkPathEscapesLstat(r, oldname); err != nil {
232 return &PathError{Op: "renameat", Path: oldname, Err: err}
233 }
234 if err := checkPathEscapesLstat(r, newname); err != nil {
235 return &PathError{Op: "renameat", Path: newname, Err: err}
236 }
237 err := Rename(joinPath(r.root.name, oldname), joinPath(r.root.name, newname))
238 if err != nil {
239 return &LinkError{"renameat", oldname, newname, underlyingError(err)}
240 }
241 return nil
242 }
243
244 func rootLink(r *Root, oldname, newname string) error {
245 if err := checkPathEscapesLstat(r, oldname); err != nil {
246 return &PathError{Op: "linkat", Path: oldname, Err: err}
247 }
248 fullOldName := joinPath(r.root.name, oldname)
249 if fs, err := Lstat(fullOldName); err == nil && fs.Mode()&ModeSymlink != 0 {
250 return &PathError{Op: "linkat", Path: oldname, Err: errors.New("cannot create a hard link to a symlink")}
251 }
252 if err := checkPathEscapesLstat(r, newname); err != nil {
253 return &PathError{Op: "linkat", Path: newname, Err: err}
254 }
255 err := Link(fullOldName, joinPath(r.root.name, newname))
256 if err != nil {
257 return &LinkError{"linkat", oldname, newname, underlyingError(err)}
258 }
259 return nil
260 }
261
262 func rootSymlink(r *Root, oldname, newname string) error {
263 if err := checkPathEscapesLstat(r, newname); err != nil {
264 return &PathError{Op: "symlinkat", Path: newname, Err: err}
265 }
266 err := Symlink(oldname, joinPath(r.root.name, newname))
267 if err != nil {
268 return &LinkError{"symlinkat", oldname, newname, underlyingError(err)}
269 }
270 return nil
271 }
272
View as plain text