github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/syscall/fs_js.go (about) 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. 4 5 // +build js,wasm 6 7 package syscall 8 9 import ( 10 "errors" 11 "io" 12 "sync" 13 "syscall/js" 14 ) 15 16 // Provided by package runtime. 17 func now() (sec int64, nsec int32) 18 19 var jsProcess = js.Global().Get("process") 20 var jsFS = js.Global().Get("fs") 21 var constants = jsFS.Get("constants") 22 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() 30 ) 31 32 type jsFile struct { 33 path string 34 entries []string 35 pos int64 36 seeked bool 37 } 38 39 var filesMu sync.Mutex 40 var files = map[int]*jsFile{ 41 0: &jsFile{}, 42 1: &jsFile{}, 43 2: &jsFile{}, 44 } 45 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 52 } 53 return f, nil 54 } 55 56 func Open(path string, openmode int, perm uint32) (int, error) { 57 if err := checkPath(path); err != nil { 58 return 0, err 59 } 60 61 flags := 0 62 if openmode&O_WRONLY != 0 { 63 flags |= nodeWRONLY 64 } 65 if openmode&O_RDWR != 0 { 66 flags |= nodeRDWR 67 } 68 if openmode&O_CREATE != 0 { 69 flags |= nodeCREATE 70 } 71 if openmode&O_TRUNC != 0 { 72 flags |= nodeTRUNC 73 } 74 if openmode&O_APPEND != 0 { 75 flags |= nodeAPPEND 76 } 77 if openmode&O_EXCL != 0 { 78 flags |= nodeEXCL 79 } 80 if openmode&O_SYNC != 0 { 81 return 0, errors.New("syscall.Open: O_SYNC is not supported by js/wasm") 82 } 83 84 jsFD, err := fsCall("open", path, flags, perm) 85 if err != nil { 86 return 0, err 87 } 88 fd := jsFD.Int() 89 90 var entries []string 91 if stat, err := fsCall("fstat", fd); err == nil && stat.Call("isDirectory").Bool() { 92 dir, err := fsCall("readdir", path) 93 if err != nil { 94 return 0, err 95 } 96 entries = make([]string, dir.Length()) 97 for i := range entries { 98 entries[i] = dir.Index(i).String() 99 } 100 } 101 102 f := &jsFile{ 103 path: path, 104 entries: entries, 105 } 106 filesMu.Lock() 107 files[fd] = f 108 filesMu.Unlock() 109 return fd, nil 110 } 111 112 func Close(fd int) error { 113 filesMu.Lock() 114 delete(files, fd) 115 filesMu.Unlock() 116 _, err := fsCall("close", fd) 117 return err 118 } 119 120 func CloseOnExec(fd int) { 121 // nothing to do - no exec 122 } 123 124 func Mkdir(path string, perm uint32) error { 125 if err := checkPath(path); err != nil { 126 return err 127 } 128 _, err := fsCall("mkdir", path, perm) 129 return err 130 } 131 132 func ReadDirent(fd int, buf []byte) (int, error) { 133 f, err := fdToFile(fd) 134 if err != nil { 135 return 0, err 136 } 137 if f.entries == nil { 138 return 0, EINVAL 139 } 140 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 147 } 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:] 154 } 155 156 return n, nil 157 } 158 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 179 } 180 181 func Stat(path string, st *Stat_t) error { 182 if err := checkPath(path); err != nil { 183 return err 184 } 185 jsSt, err := fsCall("stat", path) 186 if err != nil { 187 return err 188 } 189 setStat(st, jsSt) 190 return nil 191 } 192 193 func Lstat(path string, st *Stat_t) error { 194 if err := checkPath(path); err != nil { 195 return err 196 } 197 jsSt, err := fsCall("lstat", path) 198 if err != nil { 199 return err 200 } 201 setStat(st, jsSt) 202 return nil 203 } 204 205 func Fstat(fd int, st *Stat_t) error { 206 jsSt, err := fsCall("fstat", fd) 207 if err != nil { 208 return err 209 } 210 setStat(st, jsSt) 211 return nil 212 } 213 214 func Unlink(path string) error { 215 if err := checkPath(path); err != nil { 216 return err 217 } 218 _, err := fsCall("unlink", path) 219 return err 220 } 221 222 func Rmdir(path string) error { 223 if err := checkPath(path); err != nil { 224 return err 225 } 226 _, err := fsCall("rmdir", path) 227 return err 228 } 229 230 func Chmod(path string, mode uint32) error { 231 if err := checkPath(path); err != nil { 232 return err 233 } 234 _, err := fsCall("chmod", path, mode) 235 return err 236 } 237 238 func Fchmod(fd int, mode uint32) error { 239 _, err := fsCall("fchmod", fd, mode) 240 return err 241 } 242 243 func Chown(path string, uid, gid int) error { 244 if err := checkPath(path); err != nil { 245 return err 246 } 247 return ENOSYS 248 } 249 250 func Fchown(fd int, uid, gid int) error { 251 return ENOSYS 252 } 253 254 func Lchown(path string, uid, gid int) error { 255 if err := checkPath(path); err != nil { 256 return err 257 } 258 return ENOSYS 259 } 260 261 func UtimesNano(path string, ts []Timespec) error { 262 if err := checkPath(path); err != nil { 263 return err 264 } 265 if len(ts) != 2 { 266 return EINVAL 267 } 268 atime := ts[0].Sec 269 mtime := ts[1].Sec 270 _, err := fsCall("utimes", path, atime, mtime) 271 return err 272 } 273 274 func Rename(from, to string) error { 275 if err := checkPath(from); err != nil { 276 return err 277 } 278 if err := checkPath(to); err != nil { 279 return err 280 } 281 _, err := fsCall("rename", from, to) 282 return err 283 } 284 285 func Truncate(path string, length int64) error { 286 if err := checkPath(path); err != nil { 287 return err 288 } 289 _, err := fsCall("truncate", path, length) 290 return err 291 } 292 293 func Ftruncate(fd int, length int64) error { 294 _, err := fsCall("ftruncate", fd, length) 295 return err 296 } 297 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 303 } 304 305 func Chdir(path string) (err error) { 306 if err := checkPath(path); err != nil { 307 return err 308 } 309 defer recoverErr(&err) 310 jsProcess.Call("chdir", path) 311 return 312 } 313 314 func Fchdir(fd int) error { 315 f, err := fdToFile(fd) 316 if err != nil { 317 return err 318 } 319 return Chdir(f.path) 320 } 321 322 func Readlink(path string, buf []byte) (n int, err error) { 323 if err := checkPath(path); err != nil { 324 return 0, err 325 } 326 dst, err := fsCall("readlink", path) 327 if err != nil { 328 return 0, err 329 } 330 n = copy(buf, dst.String()) 331 return n, nil 332 } 333 334 func Link(path, link string) error { 335 if err := checkPath(path); err != nil { 336 return err 337 } 338 if err := checkPath(link); err != nil { 339 return err 340 } 341 _, err := fsCall("link", path, link) 342 return err 343 } 344 345 func Symlink(path, link string) error { 346 if err := checkPath(path); err != nil { 347 return err 348 } 349 if err := checkPath(link); err != nil { 350 return err 351 } 352 _, err := fsCall("symlink", path, link) 353 return err 354 } 355 356 func Fsync(fd int) error { 357 _, err := fsCall("fsync", fd) 358 return err 359 } 360 361 func Read(fd int, b []byte) (int, error) { 362 f, err := fdToFile(fd) 363 if err != nil { 364 return 0, err 365 } 366 367 if f.seeked { 368 n, err := Pread(fd, b, f.pos) 369 f.pos += int64(n) 370 return n, err 371 } 372 373 a := js.TypedArrayOf(b) 374 n, err := fsCall("read", fd, a, 0, len(b), nil) 375 a.Release() 376 if err != nil { 377 return 0, err 378 } 379 n2 := n.Int() 380 f.pos += int64(n2) 381 return n2, err 382 } 383 384 func Write(fd int, b []byte) (int, error) { 385 f, err := fdToFile(fd) 386 if err != nil { 387 return 0, err 388 } 389 390 if f.seeked { 391 n, err := Pwrite(fd, b, f.pos) 392 f.pos += int64(n) 393 return n, err 394 } 395 396 a := js.TypedArrayOf(b) 397 n, err := fsCall("write", fd, a, 0, len(b), nil) 398 a.Release() 399 if err != nil { 400 return 0, err 401 } 402 n2 := n.Int() 403 f.pos += int64(n2) 404 return n2, err 405 } 406 407 func Pread(fd int, b []byte, offset int64) (int, error) { 408 a := js.TypedArrayOf(b) 409 n, err := fsCall("read", fd, a, 0, len(b), offset) 410 a.Release() 411 if err != nil { 412 return 0, err 413 } 414 return n.Int(), nil 415 } 416 417 func Pwrite(fd int, b []byte, offset int64) (int, error) { 418 a := js.TypedArrayOf(b) 419 n, err := fsCall("write", fd, a, 0, len(b), offset) 420 a.Release() 421 if err != nil { 422 return 0, err 423 } 424 return n.Int(), nil 425 } 426 427 func Seek(fd int, offset int64, whence int) (int64, error) { 428 f, err := fdToFile(fd) 429 if err != nil { 430 return 0, err 431 } 432 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 443 } 444 newPos = st.Size + offset 445 default: 446 return 0, errnoErr(EINVAL) 447 } 448 449 if newPos < 0 { 450 return 0, errnoErr(EINVAL) 451 } 452 453 f.seeked = true 454 f.pos = newPos 455 return newPos, nil 456 } 457 458 func Dup(fd int) (int, error) { 459 return 0, ENOSYS 460 } 461 462 func Dup2(fd, newfd int) error { 463 return ENOSYS 464 } 465 466 func Pipe(fd []int) error { 467 return ENOSYS 468 } 469 470 func fsCall(name string, args ...interface{}) (js.Value, error) { 471 type callResult struct { 472 val js.Value 473 err error 474 } 475 476 c := make(chan callResult, 1) 477 jsFS.Call(name, append(args, js.FuncOf(func(this js.Value, args []js.Value) interface{} { 478 var res callResult 479 480 if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments 481 if jsErr := args[0]; jsErr != js.Null() { 482 res.err = mapJSError(jsErr) 483 } 484 } 485 486 res.val = js.Undefined() 487 if len(args) >= 2 { 488 res.val = args[1] 489 } 490 491 c <- res 492 return nil 493 }))...) 494 res := <-c 495 return res.val, res.err 496 } 497 498 // checkPath checks that the path is not empty and that it contains no null characters. 499 func checkPath(path string) error { 500 if path == "" { 501 return EINVAL 502 } 503 for i := 0; i < len(path); i++ { 504 if path[i] == '\x00' { 505 return EINVAL 506 } 507 } 508 return nil 509 } 510 511 func recoverErr(errPtr *error) { 512 if err := recover(); err != nil { 513 jsErr, ok := err.(js.Error) 514 if !ok { 515 panic(err) 516 } 517 *errPtr = mapJSError(jsErr.Value) 518 } 519 } 520 521 // mapJSError maps an error given by Node.js to the appropriate Go error 522 func mapJSError(jsErr js.Value) error { 523 errno, ok := errnoByCode[jsErr.Get("code").String()] 524 if !ok { 525 panic(jsErr) 526 } 527 return errnoErr(Errno(errno)) 528 }