github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/fs/vfs.go (about)

     1  package fs
     2  
     3  import (
     4  	"io"
     5  	"math/rand"
     6  	"os"
     7  	"sync"
     8  	"syscall"
     9  	"unsafe"
    10  
    11  	"github.com/icexin/eggos/console"
    12  	"github.com/icexin/eggos/fs/mount"
    13  	"github.com/icexin/eggos/kernel/isyscall"
    14  	"github.com/icexin/eggos/kernel/sys"
    15  
    16  	"github.com/spf13/afero"
    17  )
    18  
    19  var (
    20  	inodeLock sync.Mutex
    21  	inodes    []*Inode
    22  
    23  	Root = mount.NewMountableFs(afero.NewMemMapFs())
    24  )
    25  
    26  type Ioctler interface {
    27  	Ioctl(op, arg uintptr) error
    28  }
    29  
    30  type Inode struct {
    31  	File  io.ReadWriteCloser
    32  	Fd    int
    33  	inuse bool
    34  }
    35  
    36  func (i *Inode) Release() {
    37  	inodeLock.Lock()
    38  	defer inodeLock.Unlock()
    39  
    40  	i.inuse = false
    41  	i.File = nil
    42  	i.Fd = -1
    43  }
    44  
    45  func AllocInode() (int, *Inode) {
    46  	inodeLock.Lock()
    47  	defer inodeLock.Unlock()
    48  
    49  	var fd int
    50  	var ni *Inode
    51  	for i := range inodes {
    52  		entry := inodes[i]
    53  		if !entry.inuse {
    54  			fd = i
    55  			ni = entry
    56  			break
    57  		}
    58  	}
    59  	if fd == 0 {
    60  		ni = new(Inode)
    61  		fd = len(inodes)
    62  		inodes = append(inodes, ni)
    63  	}
    64  	ni.inuse = true
    65  	ni.Fd = fd
    66  	return fd, ni
    67  }
    68  
    69  func AllocFileNode(r io.ReadWriteCloser) (int, *Inode) {
    70  	fd, ni := AllocInode()
    71  	ni.File = r
    72  	return fd, ni
    73  }
    74  
    75  func GetInode(fd int) (*Inode, error) {
    76  	inodeLock.Lock()
    77  	defer inodeLock.Unlock()
    78  
    79  	if fd >= len(inodes) || fd < 0 {
    80  		return nil, syscall.EBADF
    81  	}
    82  	ni := inodes[fd]
    83  	if !ni.inuse {
    84  		return nil, syscall.EBADF
    85  	}
    86  	return ni, nil
    87  }
    88  
    89  func fscall(fn int) isyscall.Handler {
    90  	return func(c *isyscall.Request) {
    91  		var err error
    92  		if fn == syscall.SYS_OPENAT {
    93  			var fd int
    94  			fd, err = sysOpen(c.Arg(0), c.Arg(1), c.Arg(2), c.Arg(3))
    95  			if err != nil {
    96  				c.SetRet(isyscall.Error(err))
    97  			} else {
    98  				c.SetRet(uintptr(fd))
    99  			}
   100  
   101  			return
   102  		}
   103  
   104  		var ni *Inode
   105  
   106  		ni, err = GetInode(int(c.Arg(0)))
   107  		if err != nil {
   108  			c.SetRet(isyscall.Error(err))
   109  
   110  			return
   111  		}
   112  
   113  		switch fn {
   114  		case syscall.SYS_READ:
   115  			var n int
   116  			n, err = sysRead(ni, c.Arg(1), c.Arg(2))
   117  			c.SetRet(uintptr(n))
   118  		case syscall.SYS_WRITE:
   119  			var n int
   120  			n, err = sysWrite(ni, c.Arg(1), c.Arg(2))
   121  			c.SetRet(uintptr(n))
   122  		case syscall.SYS_CLOSE:
   123  			err = sysClose(ni)
   124  		case syscall.SYS_FSTAT:
   125  			err = sysStat(ni, c.Arg(1))
   126  		case syscall.SYS_IOCTL:
   127  			err = sysIoctl(ni, c.Arg(1), c.Arg(2))
   128  		}
   129  
   130  		if err != nil {
   131  			c.SetError(err)
   132  		}
   133  
   134  	}
   135  }
   136  
   137  func sysOpen(dirfd, name, flags, perm uintptr) (int, error) {
   138  	path := cstring(name)
   139  	f, err := Root.OpenFile(path, int(flags), os.FileMode(perm))
   140  	if err != nil {
   141  		if os.IsNotExist(err) {
   142  			return 0, syscall.ENOENT
   143  		}
   144  		return 0, err
   145  	}
   146  	fd, ni := AllocInode()
   147  	ni.File = f
   148  	return fd, nil
   149  }
   150  
   151  func sysClose(ni *Inode) error {
   152  	err := ni.File.Close()
   153  	ni.Release()
   154  	return err
   155  }
   156  
   157  func sysRead(ni *Inode, p, n uintptr) (int, error) {
   158  	buf := sys.UnsafeBuffer(p, int(n))
   159  	ret, err := ni.File.Read(buf)
   160  
   161  	switch {
   162  	case ret != 0:
   163  		return ret, nil
   164  	case err == io.EOF:
   165  		return 0, nil
   166  	case err != nil:
   167  		return 0, err
   168  	default:
   169  		return ret, err
   170  	}
   171  }
   172  
   173  func sysWrite(ni *Inode, p, n uintptr) (int, error) {
   174  	buf := sys.UnsafeBuffer(p, int(n))
   175  	_n, err := ni.File.Write(buf)
   176  	if _n != 0 {
   177  		return _n, nil
   178  	}
   179  	return 0, err
   180  }
   181  
   182  func sysStat(ni *Inode, statptr uintptr) error {
   183  	file, ok := ni.File.(afero.File)
   184  	if !ok {
   185  		return syscall.EINVAL
   186  	}
   187  	stat := (*syscall.Stat_t)(unsafe.Pointer(statptr))
   188  	info, err := file.Stat()
   189  	if err != nil {
   190  		return err
   191  	}
   192  	stat.Mode = uint32(info.Mode())
   193  	stat.Mtim.Sec = int64(info.ModTime().Unix())
   194  	stat.Size = info.Size()
   195  
   196  	return nil
   197  }
   198  
   199  func sysIoctl(ni *Inode, op, arg uintptr) error {
   200  	ctl, ok := ni.File.(Ioctler)
   201  	if !ok {
   202  		return syscall.EINVAL
   203  	}
   204  	return ctl.Ioctl(op, arg)
   205  }
   206  
   207  func sysFcntl(call *isyscall.Request) {
   208  	call.SetRet(0)
   209  }
   210  
   211  // func Uname(buf *Utsname)
   212  func sysUname(c *isyscall.Request) {
   213  	unsafebuf := func(b *[65]int8) []byte {
   214  		return (*[65]byte)(unsafe.Pointer(b))[:]
   215  	}
   216  	buf := (*syscall.Utsname)(unsafe.Pointer(c.Arg(0)))
   217  	copy(unsafebuf(&buf.Machine), "x86_32")
   218  	copy(unsafebuf(&buf.Domainname), "icexin.com")
   219  	copy(unsafebuf(&buf.Nodename), "icexin.local")
   220  	copy(unsafebuf(&buf.Release), "0")
   221  	copy(unsafebuf(&buf.Sysname), "eggos")
   222  	copy(unsafebuf(&buf.Version), "0")
   223  	c.SetRet(0)
   224  
   225  }
   226  
   227  // func fstatat(dirfd int, path string, stat *Stat_t, flags int)
   228  func sysFstatat64(c *isyscall.Request) {
   229  	name := cstring(c.Arg(1))
   230  	stat := (*syscall.Stat_t)(unsafe.Pointer(c.Arg(2)))
   231  	info, err := Root.Stat(name)
   232  	if err != nil {
   233  		if os.IsNotExist(err) {
   234  			c.SetRet(isyscall.Errno(syscall.ENOENT))
   235  		} else {
   236  			c.SetRet(isyscall.Error(err))
   237  		}
   238  
   239  		return
   240  	}
   241  	stat.Mode = uint32(info.Mode())
   242  	stat.Mtim.Sec = int64(info.ModTime().Unix())
   243  	stat.Size = info.Size()
   244  	c.SetRet(0)
   245  
   246  }
   247  
   248  func sysLseek(c *isyscall.Request) {
   249  	fd := c.Arg(0)
   250  	offset := c.Arg(1)
   251  	whence := c.Arg(2)
   252  
   253  	_ = offset
   254  	_ = whence
   255  
   256  	_, err := GetInode(int(fd))
   257  	if err != nil {
   258  		c.SetRet(isyscall.Error(err))
   259  		return
   260  	}
   261  	c.SetRet(0)
   262  }
   263  
   264  func sysRandom(call *isyscall.Request) {
   265  	p, n := call.Arg(0), call.Arg(1)
   266  	buf := sys.UnsafeBuffer(p, int(n))
   267  	rand.Read(buf)
   268  	call.SetRet(n)
   269  }
   270  
   271  func cstring(ptr uintptr) string {
   272  	var n int
   273  	for p := ptr; *(*byte)(unsafe.Pointer(p)) != 0; p++ {
   274  		n++
   275  	}
   276  	return string(sys.UnsafeBuffer(ptr, n))
   277  }
   278  
   279  type fileHelper struct {
   280  	r io.Reader
   281  	w io.Writer
   282  	c io.Closer
   283  }
   284  
   285  func NewFile(r io.Reader, w io.Writer, c io.Closer) io.ReadWriteCloser {
   286  	return &fileHelper{
   287  		r: r,
   288  		w: w,
   289  		c: c,
   290  	}
   291  }
   292  
   293  func (r *fileHelper) Read(p []byte) (int, error) {
   294  	if r.r != nil {
   295  		return r.r.Read(p)
   296  	}
   297  	return 0, syscall.EINVAL
   298  }
   299  func (r *fileHelper) Write(p []byte) (int, error) {
   300  	if r.w != nil {
   301  		return r.w.Write(p)
   302  	}
   303  	return 0, syscall.EROFS
   304  }
   305  
   306  func (r *fileHelper) Ioctl(op, arg uintptr) error {
   307  	var x interface{}
   308  	if r.r != nil {
   309  		x = r.r
   310  	} else {
   311  		x = r.w
   312  	}
   313  	ctl, ok := x.(Ioctler)
   314  	if !ok {
   315  		return syscall.EBADF
   316  	}
   317  	return ctl.Ioctl(op, arg)
   318  }
   319  
   320  func (r *fileHelper) Close() error {
   321  	if r.c != nil {
   322  		return r.c.Close()
   323  	}
   324  	return syscall.EINVAL
   325  }
   326  
   327  func Mount(target string, fs afero.Fs) error {
   328  	return Root.Mount(target, fs)
   329  }
   330  
   331  func vfsInit() {
   332  	c := console.Console()
   333  	// stdin
   334  	AllocFileNode(NewFile(c, nil, nil))
   335  	// stdout
   336  	AllocFileNode(NewFile(nil, c, nil))
   337  	// stderr
   338  	AllocFileNode(NewFile(nil, c, nil))
   339  	// epoll fd
   340  	AllocFileNode(NewFile(nil, nil, nil))
   341  	// pipe read fd
   342  	AllocFileNode(NewFile(nil, nil, nil))
   343  	// pipe write fd
   344  	AllocFileNode(NewFile(nil, nil, nil))
   345  
   346  	etcInit()
   347  }
   348  
   349  func sysInit() {
   350  	isyscall.Register(syscall.SYS_OPENAT, fscall(syscall.SYS_OPENAT))
   351  	isyscall.Register(syscall.SYS_WRITE, fscall(syscall.SYS_WRITE))
   352  	isyscall.Register(syscall.SYS_READ, fscall(syscall.SYS_READ))
   353  	isyscall.Register(syscall.SYS_CLOSE, fscall(syscall.SYS_CLOSE))
   354  	isyscall.Register(syscall.SYS_FSTAT, fscall(syscall.SYS_FSTAT))
   355  	isyscall.Register(syscall.SYS_IOCTL, fscall(syscall.SYS_IOCTL))
   356  	isyscall.Register(syscall.SYS_FCNTL, sysFcntl)
   357  	isyscall.Register(syscall.SYS_NEWFSTATAT, sysFstatat64)
   358  	isyscall.Register(syscall.SYS_LSEEK, sysLseek)
   359  	isyscall.Register(syscall.SYS_UNAME, sysUname)
   360  	isyscall.Register(355, sysRandom)
   361  }
   362  
   363  func Init() {
   364  	vfsInit()
   365  	sysInit()
   366  }