PR libstdc++/87308 adjust regex used in std::any pretty printer
[official-gcc.git] / libgo / go / syscall / fs_js.go
blob00d6c769791efd0ab0abfa203a2d07b8666fb27e
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build js,wasm
7 package syscall
9 import (
10 "errors"
11 "io"
12 "sync"
13 "syscall/js"
16 // Provided by package runtime.
17 func now() (sec int64, nsec int32)
19 var jsProcess = js.Global().Get("process")
20 var jsFS = js.Global().Get("fs")
21 var constants = jsFS.Get("constants")
23 var (
24 nodeWRONLY = constants.Get("O_WRONLY").Int()
25 nodeRDWR = constants.Get("O_RDWR").Int()
26 nodeCREATE = constants.Get("O_CREAT").Int()
27 nodeTRUNC = constants.Get("O_TRUNC").Int()
28 nodeAPPEND = constants.Get("O_APPEND").Int()
29 nodeEXCL = constants.Get("O_EXCL").Int()
32 type jsFile struct {
33 path string
34 entries []string
35 pos int64
36 seeked bool
39 var filesMu sync.Mutex
40 var files = map[int]*jsFile{
41 0: &jsFile{},
42 1: &jsFile{},
43 2: &jsFile{},
46 func fdToFile(fd int) (*jsFile, error) {
47 filesMu.Lock()
48 f, ok := files[fd]
49 filesMu.Unlock()
50 if !ok {
51 return nil, EBADF
53 return f, nil
56 func Open(path string, openmode int, perm uint32) (int, error) {
57 if err := checkPath(path); err != nil {
58 return 0, err
61 flags := 0
62 if openmode&O_WRONLY != 0 {
63 flags |= nodeWRONLY
65 if openmode&O_RDWR != 0 {
66 flags |= nodeRDWR
68 if openmode&O_CREATE != 0 {
69 flags |= nodeCREATE
71 if openmode&O_TRUNC != 0 {
72 flags |= nodeTRUNC
74 if openmode&O_APPEND != 0 {
75 flags |= nodeAPPEND
77 if openmode&O_EXCL != 0 {
78 flags |= nodeEXCL
80 if openmode&O_SYNC != 0 {
81 return 0, errors.New("syscall.Open: O_SYNC is not supported by js/wasm")
84 jsFD, err := fsCall("openSync", path, flags, perm)
85 if err != nil {
86 return 0, err
88 fd := jsFD.Int()
90 var entries []string
91 if stat, err := fsCall("fstatSync", fd); err == nil && stat.Call("isDirectory").Bool() {
92 dir, err := fsCall("readdirSync", path)
93 if err != nil {
94 return 0, err
96 entries = make([]string, dir.Length())
97 for i := range entries {
98 entries[i] = dir.Index(i).String()
102 f := &jsFile{
103 path: path,
104 entries: entries,
106 filesMu.Lock()
107 files[fd] = f
108 filesMu.Unlock()
109 return fd, nil
112 func Close(fd int) error {
113 filesMu.Lock()
114 delete(files, fd)
115 filesMu.Unlock()
116 _, err := fsCall("closeSync", fd)
117 return err
120 func CloseOnExec(fd int) {
121 // nothing to do - no exec
124 func Mkdir(path string, perm uint32) error {
125 if err := checkPath(path); err != nil {
126 return err
128 _, err := fsCall("mkdirSync", path, perm)
129 return err
132 func ReadDirent(fd int, buf []byte) (int, error) {
133 f, err := fdToFile(fd)
134 if err != nil {
135 return 0, err
137 if f.entries == nil {
138 return 0, EINVAL
141 n := 0
142 for len(f.entries) > 0 {
143 entry := f.entries[0]
144 l := 2 + len(entry)
145 if l > len(buf) {
146 break
148 buf[0] = byte(l)
149 buf[1] = byte(l >> 8)
150 copy(buf[2:], entry)
151 buf = buf[l:]
152 n += l
153 f.entries = f.entries[1:]
156 return n, nil
159 func setStat(st *Stat_t, jsSt js.Value) {
160 st.Dev = int64(jsSt.Get("dev").Int())
161 st.Ino = uint64(jsSt.Get("ino").Int())
162 st.Mode = uint32(jsSt.Get("mode").Int())
163 st.Nlink = uint32(jsSt.Get("nlink").Int())
164 st.Uid = uint32(jsSt.Get("uid").Int())
165 st.Gid = uint32(jsSt.Get("gid").Int())
166 st.Rdev = int64(jsSt.Get("rdev").Int())
167 st.Size = int64(jsSt.Get("size").Int())
168 st.Blksize = int32(jsSt.Get("blksize").Int())
169 st.Blocks = int32(jsSt.Get("blocks").Int())
170 atime := int64(jsSt.Get("atimeMs").Int())
171 st.Atime = atime / 1000
172 st.AtimeNsec = (atime % 1000) * 1000000
173 mtime := int64(jsSt.Get("mtimeMs").Int())
174 st.Mtime = mtime / 1000
175 st.MtimeNsec = (mtime % 1000) * 1000000
176 ctime := int64(jsSt.Get("ctimeMs").Int())
177 st.Ctime = ctime / 1000
178 st.CtimeNsec = (ctime % 1000) * 1000000
181 func Stat(path string, st *Stat_t) error {
182 if err := checkPath(path); err != nil {
183 return err
185 jsSt, err := fsCall("statSync", path)
186 if err != nil {
187 return err
189 setStat(st, jsSt)
190 return nil
193 func Lstat(path string, st *Stat_t) error {
194 if err := checkPath(path); err != nil {
195 return err
197 jsSt, err := fsCall("lstatSync", path)
198 if err != nil {
199 return err
201 setStat(st, jsSt)
202 return nil
205 func Fstat(fd int, st *Stat_t) error {
206 jsSt, err := fsCall("fstatSync", fd)
207 if err != nil {
208 return err
210 setStat(st, jsSt)
211 return nil
214 func Unlink(path string) error {
215 if err := checkPath(path); err != nil {
216 return err
218 _, err := fsCall("unlinkSync", path)
219 return err
222 func Rmdir(path string) error {
223 if err := checkPath(path); err != nil {
224 return err
226 _, err := fsCall("rmdirSync", path)
227 return err
230 func Chmod(path string, mode uint32) error {
231 if err := checkPath(path); err != nil {
232 return err
234 _, err := fsCall("chmodSync", path, mode)
235 return err
238 func Fchmod(fd int, mode uint32) error {
239 _, err := fsCall("fchmodSync", fd, mode)
240 return err
243 func Chown(path string, uid, gid int) error {
244 if err := checkPath(path); err != nil {
245 return err
247 return ENOSYS
250 func Fchown(fd int, uid, gid int) error {
251 return ENOSYS
254 func Lchown(path string, uid, gid int) error {
255 if err := checkPath(path); err != nil {
256 return err
258 return ENOSYS
261 func UtimesNano(path string, ts []Timespec) error {
262 if err := checkPath(path); err != nil {
263 return err
265 if len(ts) != 2 {
266 return EINVAL
268 atime := ts[0].Sec
269 mtime := ts[1].Sec
270 _, err := fsCall("utimesSync", path, atime, mtime)
271 return err
274 func Rename(from, to string) error {
275 if err := checkPath(from); err != nil {
276 return err
278 if err := checkPath(to); err != nil {
279 return err
281 _, err := fsCall("renameSync", from, to)
282 return err
285 func Truncate(path string, length int64) error {
286 if err := checkPath(path); err != nil {
287 return err
289 _, err := fsCall("truncateSync", path, length)
290 return err
293 func Ftruncate(fd int, length int64) error {
294 _, err := fsCall("ftruncateSync", fd, length)
295 return err
298 func Getcwd(buf []byte) (n int, err error) {
299 defer recoverErr(&err)
300 cwd := jsProcess.Call("cwd").String()
301 n = copy(buf, cwd)
302 return n, nil
305 func Chdir(path string) (err error) {
306 if err := checkPath(path); err != nil {
307 return err
309 defer recoverErr(&err)
310 jsProcess.Call("chdir", path)
311 return
314 func Fchdir(fd int) error {
315 f, err := fdToFile(fd)
316 if err != nil {
317 return err
319 return Chdir(f.path)
322 func Readlink(path string, buf []byte) (n int, err error) {
323 if err := checkPath(path); err != nil {
324 return 0, err
326 dst, err := fsCall("readlinkSync", path)
327 if err != nil {
328 return 0, err
330 n = copy(buf, dst.String())
331 return n, nil
334 func Link(path, link string) error {
335 if err := checkPath(path); err != nil {
336 return err
338 if err := checkPath(link); err != nil {
339 return err
341 _, err := fsCall("linkSync", path, link)
342 return err
345 func Symlink(path, link string) error {
346 if err := checkPath(path); err != nil {
347 return err
349 if err := checkPath(link); err != nil {
350 return err
352 _, err := fsCall("symlinkSync", path, link)
353 return err
356 func Fsync(fd int) error {
357 _, err := fsCall("fsyncSync", fd)
358 return err
361 func Read(fd int, b []byte) (int, error) {
362 f, err := fdToFile(fd)
363 if err != nil {
364 return 0, err
367 if f.seeked {
368 n, err := Pread(fd, b, f.pos)
369 f.pos += int64(n)
370 return n, err
373 a := js.TypedArrayOf(b)
374 n, err := fsCall("readSync", fd, a, 0, len(b))
375 a.Release()
376 if err != nil {
377 return 0, err
379 n2 := n.Int()
380 f.pos += int64(n2)
381 return n2, err
384 func Write(fd int, b []byte) (int, error) {
385 f, err := fdToFile(fd)
386 if err != nil {
387 return 0, err
390 if f.seeked {
391 n, err := Pwrite(fd, b, f.pos)
392 f.pos += int64(n)
393 return n, err
396 a := js.TypedArrayOf(b)
397 n, err := fsCall("writeSync", fd, a, 0, len(b))
398 a.Release()
399 if err != nil {
400 return 0, err
402 n2 := n.Int()
403 f.pos += int64(n2)
404 return n2, err
407 func Pread(fd int, b []byte, offset int64) (int, error) {
408 a := js.TypedArrayOf(b)
409 n, err := fsCall("readSync", fd, a, 0, len(b), offset)
410 a.Release()
411 if err != nil {
412 return 0, err
414 return n.Int(), nil
417 func Pwrite(fd int, b []byte, offset int64) (int, error) {
418 a := js.TypedArrayOf(b)
419 n, err := fsCall("writeSync", fd, a, 0, len(b), offset)
420 a.Release()
421 if err != nil {
422 return 0, err
424 return n.Int(), nil
427 func Seek(fd int, offset int64, whence int) (int64, error) {
428 f, err := fdToFile(fd)
429 if err != nil {
430 return 0, err
433 var newPos int64
434 switch whence {
435 case io.SeekStart:
436 newPos = offset
437 case io.SeekCurrent:
438 newPos = f.pos + offset
439 case io.SeekEnd:
440 var st Stat_t
441 if err := Fstat(fd, &st); err != nil {
442 return 0, err
444 newPos = st.Size + offset
445 default:
446 return 0, errnoErr(EINVAL)
449 if newPos < 0 {
450 return 0, errnoErr(EINVAL)
453 f.seeked = true
454 f.pos = newPos
455 return newPos, nil
458 func Dup(fd int) (int, error) {
459 return 0, ENOSYS
462 func Dup2(fd, newfd int) error {
463 return ENOSYS
466 func Pipe(fd []int) error {
467 return ENOSYS
470 func fsCall(name string, args ...interface{}) (res js.Value, err error) {
471 defer recoverErr(&err)
472 res = jsFS.Call(name, args...)
473 return
476 // checkPath checks that the path is not empty and that it contains no null characters.
477 func checkPath(path string) error {
478 if path == "" {
479 return EINVAL
481 for i := 0; i < len(path); i++ {
482 if path[i] == '\x00' {
483 return EINVAL
486 return nil
489 func recoverErr(errPtr *error) {
490 if err := recover(); err != nil {
491 jsErr, ok := err.(js.Error)
492 if !ok {
493 panic(err)
495 errno, ok := errnoByCode[jsErr.Get("code").String()]
496 if !ok {
497 panic(err)
499 *errPtr = errnoErr(Errno(errno))