github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/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/jspc/eggos/console" 12 "github.com/jspc/eggos/fs/mount" 13 "github.com/jspc/eggos/kernel/isyscall" 14 "github.com/jspc/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), "jspc.com") 219 copy(unsafebuf(&buf.Nodename), "jspc.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 }