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