1 // Copyright 2013 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 // A simulated Unix-like file system for use within NaCl. 6 // 7 // The simulation is not particularly tied to NaCl other than the reuse 8 // of NaCl's definition for the Stat_t structure. 9 // 10 // The file system need never be written to disk, so it is represented as 11 // in-memory Go data structures, never in a serialized form. 12 // 13 // TODO: Perhaps support symlinks, although they muck everything up. 14 15 package syscall 16 17 import ( 18 "sync" 19 "unsafe" 20 ) 21 22 // Provided by package runtime. 23 func now() (sec int64, nsec int32) 24 25 // An fsys is a file system. 26 // Since there is no I/O (everything is in memory), 27 // the global lock mu protects the whole file system state, 28 // and that's okay. 29 type fsys struct { 30 mu sync.Mutex 31 root *inode // root directory 32 cwd *inode // process current directory 33 inum uint64 // number of inodes created 34 dev []func() (devFile, error) // table for opening devices 35 } 36 37 // A devFile is the implementation required of device files 38 // like /dev/null or /dev/random. 39 type devFile interface { 40 pread([]byte, int64) (int, error) 41 pwrite([]byte, int64) (int, error) 42 } 43 44 // An inode is a (possibly special) file in the file system. 45 type inode struct { 46 Stat_t 47 data []byte 48 dir []dirent 49 } 50 51 // A dirent describes a single directory entry. 52 type dirent struct { 53 name string 54 inode *inode 55 } 56 57 // An fsysFile is the fileImpl implementation backed by the file system. 58 type fsysFile struct { 59 defaultFileImpl 60 fsys *fsys 61 inode *inode 62 openmode int 63 offset int64 64 dev devFile 65 } 66 67 // newFsys creates a new file system. 68 func newFsys() *fsys { 69 fs := &fsys{} 70 fs.mu.Lock() 71 defer fs.mu.Unlock() 72 ip := fs.newInode() 73 ip.Mode = 0555 | S_IFDIR 74 fs.dirlink(ip, ".", ip) 75 fs.dirlink(ip, "..", ip) 76 fs.cwd = ip 77 fs.root = ip 78 return fs 79 } 80 81 var fs = newFsys() 82 var fsinit = func() {} 83 84 func init() { 85 // do not trigger loading of zipped file system here 86 oldFsinit := fsinit 87 defer func() { fsinit = oldFsinit }() 88 fsinit = func() {} 89 Mkdir("/dev", 0555) 90 Mkdir("/tmp", 0777) 91 mkdev("/dev/null", 0666, openNull) 92 mkdev("/dev/random", 0444, openRandom) 93 mkdev("/dev/urandom", 0444, openRandom) 94 mkdev("/dev/zero", 0666, openZero) 95 chdirEnv() 96 } 97 98 func chdirEnv() { 99 pwd, ok := Getenv("NACLPWD") 100 if ok { 101 chdir(pwd) 102 } 103 } 104 105 // Except where indicated otherwise, unexported methods on fsys 106 // expect fs.mu to have been locked by the caller. 107 108 // newInode creates a new inode. 109 func (fs *fsys) newInode() *inode { 110 fs.inum++ 111 ip := &inode{ 112 Stat_t: Stat_t{ 113 Ino: fs.inum, 114 Blksize: 512, 115 }, 116 } 117 return ip 118 } 119 120 // atime sets ip.Atime to the current time. 121 func (fs *fsys) atime(ip *inode) { 122 sec, nsec := now() 123 ip.Atime, ip.AtimeNsec = sec, int64(nsec) 124 } 125 126 // mtime sets ip.Mtime to the current time. 127 func (fs *fsys) mtime(ip *inode) { 128 sec, nsec := now() 129 ip.Mtime, ip.MtimeNsec = sec, int64(nsec) 130 } 131 132 // dirlookup looks for an entry in the directory dp with the given name. 133 // It returns the directory entry and its index within the directory. 134 func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) { 135 fs.atime(dp) 136 for i := range dp.dir { 137 de := &dp.dir[i] 138 if de.name == name { 139 fs.atime(de.inode) 140 return de, i, nil 141 } 142 } 143 return nil, 0, ENOENT 144 } 145 146 // dirlink adds to the directory dp an entry for name pointing at the inode ip. 147 // If dp already contains an entry for name, that entry is overwritten. 148 func (fs *fsys) dirlink(dp *inode, name string, ip *inode) { 149 fs.mtime(dp) 150 fs.atime(ip) 151 ip.Nlink++ 152 for i := range dp.dir { 153 if dp.dir[i].name == name { 154 dp.dir[i] = dirent{name, ip} 155 return 156 } 157 } 158 dp.dir = append(dp.dir, dirent{name, ip}) 159 dp.dirSize() 160 } 161 162 func (dp *inode) dirSize() { 163 dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent 164 } 165 166 // skipelem splits path into the first element and the remainder. 167 // the returned first element contains no slashes, and the returned 168 // remainder does not begin with a slash. 169 func skipelem(path string) (elem, rest string) { 170 for len(path) > 0 && path[0] == '/' { 171 path = path[1:] 172 } 173 if len(path) == 0 { 174 return "", "" 175 } 176 i := 0 177 for i < len(path) && path[i] != '/' { 178 i++ 179 } 180 elem, path = path[:i], path[i:] 181 for len(path) > 0 && path[0] == '/' { 182 path = path[1:] 183 } 184 return elem, path 185 } 186 187 // namei translates a file system path name into an inode. 188 // If parent is false, the returned ip corresponds to the given name, and elem is the empty string. 189 // If parent is true, the walk stops at the next-to-last element in the name, 190 // so that ip is the parent directory and elem is the final element in the path. 191 func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) { 192 // Reject NUL in name. 193 for i := 0; i < len(path); i++ { 194 if path[i] == '\x00' { 195 return nil, "", EINVAL 196 } 197 } 198 199 // Reject empty name. 200 if path == "" { 201 return nil, "", EINVAL 202 } 203 204 if path[0] == '/' { 205 ip = fs.root 206 } else { 207 ip = fs.cwd 208 } 209 210 for len(path) > 0 && path[len(path)-1] == '/' { 211 path = path[:len(path)-1] 212 } 213 214 for { 215 elem, rest := skipelem(path) 216 if elem == "" { 217 if parent && ip.Mode&S_IFMT == S_IFDIR { 218 return ip, ".", nil 219 } 220 break 221 } 222 if ip.Mode&S_IFMT != S_IFDIR { 223 return nil, "", ENOTDIR 224 } 225 if len(elem) >= 256 { 226 return nil, "", ENAMETOOLONG 227 } 228 if parent && rest == "" { 229 // Stop one level early. 230 return ip, elem, nil 231 } 232 de, _, err := fs.dirlookup(ip, elem) 233 if err != nil { 234 return nil, "", err 235 } 236 ip = de.inode 237 path = rest 238 } 239 if parent { 240 return nil, "", ENOTDIR 241 } 242 return ip, "", nil 243 } 244 245 // open opens or creates a file with the given name, open mode, 246 // and permission mode bits. 247 func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) { 248 dp, elem, err := fs.namei(name, true) 249 if err != nil { 250 return nil, err 251 } 252 var ( 253 ip *inode 254 dev devFile 255 ) 256 de, _, err := fs.dirlookup(dp, elem) 257 if err != nil { 258 if openmode&O_CREATE == 0 { 259 return nil, err 260 } 261 ip = fs.newInode() 262 ip.Mode = mode 263 fs.dirlink(dp, elem, ip) 264 if ip.Mode&S_IFMT == S_IFDIR { 265 fs.dirlink(ip, ".", ip) 266 fs.dirlink(ip, "..", dp) 267 } 268 } else { 269 ip = de.inode 270 if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL { 271 return nil, EEXIST 272 } 273 if openmode&O_TRUNC != 0 { 274 if ip.Mode&S_IFMT == S_IFDIR { 275 return nil, EISDIR 276 } 277 ip.data = nil 278 } 279 if ip.Mode&S_IFMT == S_IFCHR { 280 if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil { 281 return nil, ENODEV 282 } 283 dev, err = fs.dev[ip.Rdev]() 284 if err != nil { 285 return nil, err 286 } 287 } 288 } 289 290 switch openmode & O_ACCMODE { 291 case O_WRONLY, O_RDWR: 292 if ip.Mode&S_IFMT == S_IFDIR { 293 return nil, EISDIR 294 } 295 } 296 297 switch ip.Mode & S_IFMT { 298 case S_IFDIR: 299 if openmode&O_ACCMODE != O_RDONLY { 300 return nil, EISDIR 301 } 302 303 case S_IFREG: 304 // ok 305 306 case S_IFCHR: 307 // handled above 308 309 default: 310 // TODO: some kind of special file 311 return nil, EPERM 312 } 313 314 f := &fsysFile{ 315 fsys: fs, 316 inode: ip, 317 openmode: openmode, 318 dev: dev, 319 } 320 if openmode&O_APPEND != 0 { 321 f.offset = ip.Size 322 } 323 return f, nil 324 } 325 326 // fsysFile methods to implement fileImpl. 327 328 func (f *fsysFile) stat(st *Stat_t) error { 329 f.fsys.mu.Lock() 330 defer f.fsys.mu.Unlock() 331 *st = f.inode.Stat_t 332 return nil 333 } 334 335 func (f *fsysFile) read(b []byte) (int, error) { 336 f.fsys.mu.Lock() 337 defer f.fsys.mu.Unlock() 338 n, err := f.preadLocked(b, f.offset) 339 f.offset += int64(n) 340 return n, err 341 } 342 343 func ReadDirent(fd int, buf []byte) (int, error) { 344 f, err := fdToFsysFile(fd) 345 if err != nil { 346 return 0, err 347 } 348 f.fsys.mu.Lock() 349 defer f.fsys.mu.Unlock() 350 if f.inode.Mode&S_IFMT != S_IFDIR { 351 return 0, EINVAL 352 } 353 n, err := f.preadLocked(buf, f.offset) 354 f.offset += int64(n) 355 return n, err 356 } 357 358 func (f *fsysFile) write(b []byte) (int, error) { 359 f.fsys.mu.Lock() 360 defer f.fsys.mu.Unlock() 361 n, err := f.pwriteLocked(b, f.offset) 362 f.offset += int64(n) 363 return n, err 364 } 365 366 func (f *fsysFile) seek(offset int64, whence int) (int64, error) { 367 f.fsys.mu.Lock() 368 defer f.fsys.mu.Unlock() 369 switch whence { 370 case 1: 371 offset += f.offset 372 case 2: 373 offset += f.inode.Size 374 } 375 if offset < 0 { 376 return 0, EINVAL 377 } 378 if offset > f.inode.Size { 379 return 0, EINVAL 380 } 381 f.offset = offset 382 return offset, nil 383 } 384 385 func (f *fsysFile) pread(b []byte, offset int64) (int, error) { 386 f.fsys.mu.Lock() 387 defer f.fsys.mu.Unlock() 388 return f.preadLocked(b, offset) 389 } 390 391 func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) { 392 f.fsys.mu.Lock() 393 defer f.fsys.mu.Unlock() 394 return f.pwriteLocked(b, offset) 395 } 396 397 func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) { 398 if f.openmode&O_ACCMODE == O_WRONLY { 399 return 0, EINVAL 400 } 401 if offset < 0 { 402 return 0, EINVAL 403 } 404 if f.dev != nil { 405 f.fsys.atime(f.inode) 406 f.fsys.mu.Unlock() 407 defer f.fsys.mu.Lock() 408 return f.dev.pread(b, offset) 409 } 410 if offset > f.inode.Size { 411 return 0, nil 412 } 413 if int64(len(b)) > f.inode.Size-offset { 414 b = b[:f.inode.Size-offset] 415 } 416 417 if f.inode.Mode&S_IFMT == S_IFDIR { 418 if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize { 419 return 0, EINVAL 420 } 421 fs.atime(f.inode) 422 n := 0 423 for len(b) >= direntSize { 424 src := f.inode.dir[int(offset/direntSize)] 425 dst := (*Dirent)(unsafe.Pointer(&b[0])) 426 dst.Ino = int64(src.inode.Ino) 427 dst.Off = offset 428 dst.Reclen = direntSize 429 for i := range dst.Name { 430 dst.Name[i] = 0 431 } 432 copy(dst.Name[:], src.name) 433 n += direntSize 434 offset += direntSize 435 b = b[direntSize:] 436 } 437 return n, nil 438 } 439 440 fs.atime(f.inode) 441 n := copy(b, f.inode.data[offset:]) 442 return n, nil 443 } 444 445 func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) { 446 if f.openmode&O_ACCMODE == O_RDONLY { 447 return 0, EINVAL 448 } 449 if offset < 0 { 450 return 0, EINVAL 451 } 452 if f.dev != nil { 453 f.fsys.atime(f.inode) 454 f.fsys.mu.Unlock() 455 defer f.fsys.mu.Lock() 456 return f.dev.pwrite(b, offset) 457 } 458 if offset > f.inode.Size { 459 return 0, EINVAL 460 } 461 f.fsys.mtime(f.inode) 462 n := copy(f.inode.data[offset:], b) 463 if n < len(b) { 464 f.inode.data = append(f.inode.data, b[n:]...) 465 f.inode.Size = int64(len(f.inode.data)) 466 } 467 return len(b), nil 468 } 469 470 // Standard Unix system calls. 471 472 func Open(path string, openmode int, perm uint32) (fd int, err error) { 473 fsinit() 474 fs.mu.Lock() 475 defer fs.mu.Unlock() 476 f, err := fs.open(path, openmode, perm&0777|S_IFREG) 477 if err != nil { 478 return -1, err 479 } 480 return newFD(f), nil 481 } 482 483 func Mkdir(path string, perm uint32) error { 484 fs.mu.Lock() 485 defer fs.mu.Unlock() 486 _, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR) 487 return err 488 } 489 490 func Getcwd(buf []byte) (n int, err error) { 491 // Force package os to default to the old algorithm using .. and directory reads. 492 return 0, ENOSYS 493 } 494 495 func Stat(path string, st *Stat_t) error { 496 fsinit() 497 fs.mu.Lock() 498 defer fs.mu.Unlock() 499 ip, _, err := fs.namei(path, false) 500 if err != nil { 501 return err 502 } 503 *st = ip.Stat_t 504 return nil 505 } 506 507 func Lstat(path string, st *Stat_t) error { 508 return Stat(path, st) 509 } 510 511 func unlink(path string, isdir bool) error { 512 fsinit() 513 fs.mu.Lock() 514 defer fs.mu.Unlock() 515 dp, elem, err := fs.namei(path, true) 516 if err != nil { 517 return err 518 } 519 if elem == "." || elem == ".." { 520 return EINVAL 521 } 522 de, _, err := fs.dirlookup(dp, elem) 523 if err != nil { 524 return err 525 } 526 if isdir { 527 if de.inode.Mode&S_IFMT != S_IFDIR { 528 return ENOTDIR 529 } 530 if len(de.inode.dir) != 2 { 531 return ENOTEMPTY 532 } 533 } else { 534 if de.inode.Mode&S_IFMT == S_IFDIR { 535 return EISDIR 536 } 537 } 538 de.inode.Nlink-- 539 *de = dp.dir[len(dp.dir)-1] 540 dp.dir = dp.dir[:len(dp.dir)-1] 541 dp.dirSize() 542 return nil 543 } 544 545 func Unlink(path string) error { 546 return unlink(path, false) 547 } 548 549 func Rmdir(path string) error { 550 return unlink(path, true) 551 } 552 553 func Chmod(path string, mode uint32) error { 554 fsinit() 555 fs.mu.Lock() 556 defer fs.mu.Unlock() 557 ip, _, err := fs.namei(path, false) 558 if err != nil { 559 return err 560 } 561 ip.Mode = ip.Mode&^0777 | mode&0777 562 return nil 563 } 564 565 func Fchmod(fd int, mode uint32) error { 566 f, err := fdToFsysFile(fd) 567 if err != nil { 568 return err 569 } 570 f.fsys.mu.Lock() 571 defer f.fsys.mu.Unlock() 572 f.inode.Mode = f.inode.Mode&^0777 | mode&0777 573 return nil 574 } 575 576 func Chown(path string, uid, gid int) error { 577 fsinit() 578 fs.mu.Lock() 579 defer fs.mu.Unlock() 580 ip, _, err := fs.namei(path, false) 581 if err != nil { 582 return err 583 } 584 ip.Uid = uint32(uid) 585 ip.Gid = uint32(gid) 586 return nil 587 } 588 589 func Fchown(fd int, uid, gid int) error { 590 fs.mu.Lock() 591 defer fs.mu.Unlock() 592 f, err := fdToFsysFile(fd) 593 if err != nil { 594 return err 595 } 596 f.fsys.mu.Lock() 597 defer f.fsys.mu.Unlock() 598 f.inode.Uid = uint32(uid) 599 f.inode.Gid = uint32(gid) 600 return nil 601 } 602 603 func Lchown(path string, uid, gid int) error { 604 return Chown(path, uid, gid) 605 } 606 607 func UtimesNano(path string, ts []Timespec) error { 608 if len(ts) != 2 { 609 return EINVAL 610 } 611 fsinit() 612 fs.mu.Lock() 613 defer fs.mu.Unlock() 614 ip, _, err := fs.namei(path, false) 615 if err != nil { 616 return err 617 } 618 ip.Atime = ts[0].Sec 619 ip.AtimeNsec = int64(ts[0].Nsec) 620 ip.Mtime = ts[1].Sec 621 ip.MtimeNsec = int64(ts[1].Nsec) 622 return nil 623 } 624 625 func Link(path, link string) error { 626 fsinit() 627 ip, _, err := fs.namei(path, false) 628 if err != nil { 629 return err 630 } 631 dp, elem, err := fs.namei(link, true) 632 if err != nil { 633 return err 634 } 635 if ip.Mode&S_IFMT == S_IFDIR { 636 return EPERM 637 } 638 fs.dirlink(dp, elem, ip) 639 return nil 640 } 641 642 func Rename(from, to string) error { 643 fsinit() 644 fdp, felem, err := fs.namei(from, true) 645 if err != nil { 646 return err 647 } 648 fde, _, err := fs.dirlookup(fdp, felem) 649 if err != nil { 650 return err 651 } 652 tdp, telem, err := fs.namei(to, true) 653 if err != nil { 654 return err 655 } 656 fs.dirlink(tdp, telem, fde.inode) 657 fde.inode.Nlink-- 658 *fde = fdp.dir[len(fdp.dir)-1] 659 fdp.dir = fdp.dir[:len(fdp.dir)-1] 660 fdp.dirSize() 661 return nil 662 } 663 664 func (fs *fsys) truncate(ip *inode, length int64) error { 665 if length > 1e9 || ip.Mode&S_IFMT != S_IFREG { 666 return EINVAL 667 } 668 if length < int64(len(ip.data)) { 669 ip.data = ip.data[:length] 670 } else { 671 data := make([]byte, length) 672 copy(data, ip.data) 673 ip.data = data 674 } 675 ip.Size = int64(len(ip.data)) 676 return nil 677 } 678 679 func Truncate(path string, length int64) error { 680 fsinit() 681 fs.mu.Lock() 682 defer fs.mu.Unlock() 683 ip, _, err := fs.namei(path, false) 684 if err != nil { 685 return err 686 } 687 return fs.truncate(ip, length) 688 } 689 690 func Ftruncate(fd int, length int64) error { 691 f, err := fdToFsysFile(fd) 692 if err != nil { 693 return err 694 } 695 f.fsys.mu.Lock() 696 defer f.fsys.mu.Unlock() 697 return f.fsys.truncate(f.inode, length) 698 } 699 700 func Chdir(path string) error { 701 fsinit() 702 return chdir(path) 703 } 704 705 func chdir(path string) error { 706 fs.mu.Lock() 707 defer fs.mu.Unlock() 708 ip, _, err := fs.namei(path, false) 709 if err != nil { 710 return err 711 } 712 fs.cwd = ip 713 return nil 714 } 715 716 func Fchdir(fd int) error { 717 f, err := fdToFsysFile(fd) 718 if err != nil { 719 return err 720 } 721 f.fsys.mu.Lock() 722 defer f.fsys.mu.Unlock() 723 if f.inode.Mode&S_IFMT != S_IFDIR { 724 return ENOTDIR 725 } 726 fs.cwd = f.inode 727 return nil 728 } 729 730 func Readlink(path string, buf []byte) (n int, err error) { 731 return 0, ENOSYS 732 } 733 734 func Symlink(path, link string) error { 735 return ENOSYS 736 } 737 738 func Fsync(fd int) error { 739 return nil 740 } 741 742 // Special devices. 743 744 func mkdev(path string, mode uint32, open func() (devFile, error)) error { 745 f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode) 746 if err != nil { 747 return err 748 } 749 ip := f.(*fsysFile).inode 750 ip.Rdev = int64(len(fs.dev)) 751 fs.dev = append(fs.dev, open) 752 return nil 753 } 754 755 type nullFile struct{} 756 757 func openNull() (devFile, error) { return &nullFile{}, nil } 758 func (f *nullFile) close() error { return nil } 759 func (f *nullFile) pread(b []byte, offset int64) (int, error) { return 0, nil } 760 func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil } 761 762 type zeroFile struct{} 763 764 func openZero() (devFile, error) { return &zeroFile{}, nil } 765 func (f *zeroFile) close() error { return nil } 766 func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil } 767 768 func (f *zeroFile) pread(b []byte, offset int64) (int, error) { 769 for i := range b { 770 b[i] = 0 771 } 772 return len(b), nil 773 } 774 775 type randomFile struct{} 776 777 func openRandom() (devFile, error) { 778 return randomFile{}, nil 779 } 780 781 func (f randomFile) close() error { 782 return nil 783 } 784 785 func (f randomFile) pread(b []byte, offset int64) (int, error) { 786 if err := naclGetRandomBytes(b); err != nil { 787 return 0, err 788 } 789 return len(b), nil 790 } 791 792 func (f randomFile) pwrite(b []byte, offset int64) (int, error) { 793 return 0, EPERM 794 } 795 796 func fdToFsysFile(fd int) (*fsysFile, error) { 797 f, err := fdToFile(fd) 798 if err != nil { 799 return nil, err 800 } 801 impl := f.impl 802 fsysf, ok := impl.(*fsysFile) 803 if !ok { 804 return nil, EINVAL 805 } 806 return fsysf, nil 807 } 808 809 // create creates a file in the file system with the given name, mode, time, and data. 810 // It is meant to be called when initializing the file system image. 811 func create(name string, mode uint32, sec int64, data []byte) error { 812 fs.mu.Lock() 813 defer fs.mu.Unlock() 814 f, err := fs.open(name, O_CREATE|O_EXCL, mode) 815 if err != nil { 816 if mode&S_IFMT == S_IFDIR { 817 ip, _, err := fs.namei(name, false) 818 if err == nil && (ip.Mode&S_IFMT) == S_IFDIR { 819 return nil // directory already exists 820 } 821 } 822 return err 823 } 824 ip := f.(*fsysFile).inode 825 ip.Atime = sec 826 ip.Mtime = sec 827 ip.Ctime = sec 828 if len(data) > 0 { 829 ip.Size = int64(len(data)) 830 ip.data = data 831 } 832 return nil 833 } 834