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
191
192 for len(name) > 0 && IsPathSeparator(name[len(name)-1]) {
193 name = name[:len(name)-1]
194 }
195 if endsWithDot(name) {
196
197 return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL}
198 }
199 if err := checkPathEscapesLstat(r, name); err != nil {
200 if err == syscall.ENOTDIR {
201
202
203 return nil
204 }
205 return &PathError{Op: "RemoveAll", Path: name, Err: err}
206 }
207 if err := RemoveAll(joinPath(r.root.name, name)); err != nil {
208 return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)}
209 }
210 return nil
211 }
212
213 func rootReadlink(r *Root, name string) (string, error) {
214 if err := checkPathEscapesLstat(r, name); err != nil {
215 return "", &PathError{Op: "readlinkat", Path: name, Err: err}
216 }
217 name, err := Readlink(joinPath(r.root.name, name))
218 if err != nil {
219 return "", &PathError{Op: "readlinkat", Path: name, Err: underlyingError(err)}
220 }
221 return name, nil
222 }
223
224 func rootRename(r *Root, oldname, newname string) error {
225 if err := checkPathEscapesLstat(r, oldname); err != nil {
226 return &PathError{Op: "renameat", Path: oldname, Err: err}
227 }
228 if err := checkPathEscapesLstat(r, newname); err != nil {
229 return &PathError{Op: "renameat", Path: newname, Err: err}
230 }
231 err := Rename(joinPath(r.root.name, oldname), joinPath(r.root.name, newname))
232 if err != nil {
233 return &LinkError{"renameat", oldname, newname, underlyingError(err)}
234 }
235 return nil
236 }
237
238 func rootLink(r *Root, oldname, newname string) error {
239 if err := checkPathEscapesLstat(r, oldname); err != nil {
240 return &PathError{Op: "linkat", Path: oldname, Err: err}
241 }
242 fullOldName := joinPath(r.root.name, oldname)
243 if fs, err := Lstat(fullOldName); err == nil && fs.Mode()&ModeSymlink != 0 {
244 return &PathError{Op: "linkat", Path: oldname, Err: errors.New("cannot create a hard link to a symlink")}
245 }
246 if err := checkPathEscapesLstat(r, newname); err != nil {
247 return &PathError{Op: "linkat", Path: newname, Err: err}
248 }
249 err := Link(fullOldName, joinPath(r.root.name, newname))
250 if err != nil {
251 return &LinkError{"linkat", oldname, newname, underlyingError(err)}
252 }
253 return nil
254 }
255
256 func rootSymlink(r *Root, oldname, newname string) error {
257 if err := checkPathEscapesLstat(r, newname); err != nil {
258 return &PathError{Op: "symlinkat", Path: newname, Err: err}
259 }
260 err := Symlink(oldname, joinPath(r.root.name, newname))
261 if err != nil {
262 return &LinkError{"symlinkat", oldname, newname, underlyingError(err)}
263 }
264 return nil
265 }
266
View as plain text