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