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.
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")
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()
39 var filesMu sync
.Mutex
40 var files
= map[int]*jsFile
{
46 func fdToFile(fd
int) (*jsFile
, error
) {
56 func Open(path
string, openmode
int, perm
uint32) (int, error
) {
57 if err
:= checkPath(path
); err
!= nil {
62 if openmode
&O_WRONLY
!= 0 {
65 if openmode
&O_RDWR
!= 0 {
68 if openmode
&O_CREATE
!= 0 {
71 if openmode
&O_TRUNC
!= 0 {
74 if openmode
&O_APPEND
!= 0 {
77 if openmode
&O_EXCL
!= 0 {
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
)
91 if stat
, err
:= fsCall("fstatSync", fd
); err
== nil && stat
.Call("isDirectory").Bool() {
92 dir
, err
:= fsCall("readdirSync", path
)
96 entries
= make([]string, dir
.Length())
97 for i
:= range entries
{
98 entries
[i
] = dir
.Index(i
).String()
112 func Close(fd
int) error
{
116 _
, err
:= fsCall("closeSync", fd
)
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 {
128 _
, err
:= fsCall("mkdirSync", path
, perm
)
132 func ReadDirent(fd
int, buf
[]byte) (int, error
) {
133 f
, err
:= fdToFile(fd
)
137 if f
.entries
== nil {
142 for len(f
.entries
) > 0 {
143 entry
:= f
.entries
[0]
149 buf
[1] = byte(l
>> 8)
153 f
.entries
= f
.entries
[1:]
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 {
185 jsSt
, err
:= fsCall("statSync", path
)
193 func Lstat(path
string, st
*Stat_t
) error
{
194 if err
:= checkPath(path
); err
!= nil {
197 jsSt
, err
:= fsCall("lstatSync", path
)
205 func Fstat(fd
int, st
*Stat_t
) error
{
206 jsSt
, err
:= fsCall("fstatSync", fd
)
214 func Unlink(path
string) error
{
215 if err
:= checkPath(path
); err
!= nil {
218 _
, err
:= fsCall("unlinkSync", path
)
222 func Rmdir(path
string) error
{
223 if err
:= checkPath(path
); err
!= nil {
226 _
, err
:= fsCall("rmdirSync", path
)
230 func Chmod(path
string, mode
uint32) error
{
231 if err
:= checkPath(path
); err
!= nil {
234 _
, err
:= fsCall("chmodSync", path
, mode
)
238 func Fchmod(fd
int, mode
uint32) error
{
239 _
, err
:= fsCall("fchmodSync", fd
, mode
)
243 func Chown(path
string, uid
, gid
int) error
{
244 if err
:= checkPath(path
); err
!= nil {
250 func Fchown(fd
int, uid
, gid
int) error
{
254 func Lchown(path
string, uid
, gid
int) error
{
255 if err
:= checkPath(path
); err
!= nil {
261 func UtimesNano(path
string, ts
[]Timespec
) error
{
262 if err
:= checkPath(path
); err
!= nil {
270 _
, err
:= fsCall("utimesSync", path
, atime
, mtime
)
274 func Rename(from
, to
string) error
{
275 if err
:= checkPath(from
); err
!= nil {
278 if err
:= checkPath(to
); err
!= nil {
281 _
, err
:= fsCall("renameSync", from
, to
)
285 func Truncate(path
string, length
int64) error
{
286 if err
:= checkPath(path
); err
!= nil {
289 _
, err
:= fsCall("truncateSync", path
, length
)
293 func Ftruncate(fd
int, length
int64) error
{
294 _
, err
:= fsCall("ftruncateSync", fd
, length
)
298 func Getcwd(buf
[]byte) (n
int, err error
) {
299 defer recoverErr(&err
)
300 cwd
:= jsProcess
.Call("cwd").String()
305 func Chdir(path
string) (err error
) {
306 if err
:= checkPath(path
); err
!= nil {
309 defer recoverErr(&err
)
310 jsProcess
.Call("chdir", path
)
314 func Fchdir(fd
int) error
{
315 f
, err
:= fdToFile(fd
)
322 func Readlink(path
string, buf
[]byte) (n
int, err error
) {
323 if err
:= checkPath(path
); err
!= nil {
326 dst
, err
:= fsCall("readlinkSync", path
)
330 n
= copy(buf
, dst
.String())
334 func Link(path
, link
string) error
{
335 if err
:= checkPath(path
); err
!= nil {
338 if err
:= checkPath(link
); err
!= nil {
341 _
, err
:= fsCall("linkSync", path
, link
)
345 func Symlink(path
, link
string) error
{
346 if err
:= checkPath(path
); err
!= nil {
349 if err
:= checkPath(link
); err
!= nil {
352 _
, err
:= fsCall("symlinkSync", path
, link
)
356 func Fsync(fd
int) error
{
357 _
, err
:= fsCall("fsyncSync", fd
)
361 func Read(fd
int, b
[]byte) (int, error
) {
362 f
, err
:= fdToFile(fd
)
368 n
, err
:= Pread(fd
, b
, f
.pos
)
373 a
:= js
.TypedArrayOf(b
)
374 n
, err
:= fsCall("readSync", fd
, a
, 0, len(b
))
384 func Write(fd
int, b
[]byte) (int, error
) {
385 f
, err
:= fdToFile(fd
)
391 n
, err
:= Pwrite(fd
, b
, f
.pos
)
396 a
:= js
.TypedArrayOf(b
)
397 n
, err
:= fsCall("writeSync", fd
, a
, 0, len(b
))
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
)
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
)
427 func Seek(fd
int, offset
int64, whence
int) (int64, error
) {
428 f
, err
:= fdToFile(fd
)
438 newPos
= f
.pos
+ offset
441 if err
:= Fstat(fd
, &st
); err
!= nil {
444 newPos
= st
.Size
+ offset
446 return 0, errnoErr(EINVAL
)
450 return 0, errnoErr(EINVAL
)
458 func Dup(fd
int) (int, error
) {
462 func Dup2(fd
, newfd
int) error
{
466 func Pipe(fd
[]int) error
{
470 func fsCall(name
string, args
...interface{}) (res js
.Value
, err error
) {
471 defer recoverErr(&err
)
472 res
= jsFS
.Call(name
, args
...)
476 // checkPath checks that the path is not empty and that it contains no null characters.
477 func checkPath(path
string) error
{
481 for i
:= 0; i
< len(path
); i
++ {
482 if path
[i
] == '\x00' {
489 func recoverErr(errPtr
*error
) {
490 if err
:= recover(); err
!= nil {
491 jsErr
, ok
:= err
.(js
.Error
)
495 errno
, ok
:= errnoByCode
[jsErr
.Get("code").String()]
499 *errPtr
= errnoErr(Errno(errno
))