lib9p

Go 9P library.
Log | Files | Refs | LICENSE

main.go (4043B)


      1 package main
      2 
      3 import (
      4 	"bytes"
      5 	"context"
      6 	"flag"
      7 	"fmt"
      8 	"io"
      9 	"io/fs"
     10 	"log"
     11 	"net"
     12 	"os"
     13 	"strings"
     14 
     15 	"git.mtkn.jp/lib9p"
     16 )
     17 
     18 type numFS struct {
     19 	root *numFile
     20 }
     21 
     22 func (fsys *numFS) String() string {
     23 	if fsys.root == nil {
     24 		return "<empty>"
     25 	}
     26 	return fsysString(fsys.root)
     27 }
     28 
     29 func fsysString(f *numFile) string {
     30 	s := fmt.Sprintf("%d\n", f.id)
     31 	for _, c := range f.children {
     32 		cs := fsysString(c)
     33 		ln := strings.Split(cs, "\n")
     34 		for _, l := range ln {
     35 			s += "\t" + l + "\n"
     36 		}
     37 	}
     38 	return s
     39 }
     40 
     41 func (fsys *numFS) OpenFile(name string, _ int) (lib9p.File, error) {
     42 	if name == "." || name == "" {
     43 		return fsys.root, nil
     44 	}
     45 	wname := strings.Split(name, "/")
     46 	cwd := fsys.root
     47 L:
     48 	for _, wn := range wname {
     49 		for _, c := range cwd.children {
     50 			if fmt.Sprintf("%d", c.id) == wn {
     51 				cwd = c
     52 				continue L
     53 			}
     54 		}
     55 		return nil, fmt.Errorf("not found")
     56 	}
     57 	return cwd, nil
     58 }
     59 
     60 // This function assumes that group and uid both exist and
     61 // the leader of group has the same name as group itself.
     62 func (fsys *numFS) IsGroupLeader(group, uid string) bool {
     63 	return group == uid
     64 }
     65 
     66 // This function assumes that group and uid both exists and
     67 // only the member of group has the same name as group itself.
     68 func (fsys *numFS) IsGroupMember(group, uid string) bool {
     69 	return group == uid
     70 }
     71 
     72 type numFile struct {
     73 	fs       *numFS
     74 	id       int
     75 	reader   *bytes.Reader
     76 	children []*numFile
     77 }
     78 
     79 func (f *numFile) Fsys() lib9p.FS { return f.fs }
     80 
     81 func (f *numFile) Stat() (*lib9p.FileInfo, error) {
     82 	var stat lib9p.Stat
     83 	stat.Type = 0
     84 	stat.Dev = 0
     85 	if f.id == -1 {
     86 		stat.Qid = lib9p.Qid{
     87 			Type: lib9p.QTDIR,
     88 			Vers: 0,
     89 			Path: ^uint64(0),
     90 		}
     91 	} else {
     92 		stat.Qid = lib9p.Qid{
     93 			Type: lib9p.QTFILE,
     94 			Vers: 0,
     95 			Path: uint64(f.id),
     96 		}
     97 	}
     98 	var mode lib9p.FileMode
     99 	if f.id == -1 {
    100 		mode |= fs.ModeDir
    101 	}
    102 	mode |= 0444
    103 	stat.Mode = mode
    104 	stat.Atime = 0
    105 	stat.Mtime = 0
    106 	var length int64
    107 	if f.id == -1 {
    108 		length = 0
    109 	} else {
    110 		length = f.reader.Size()
    111 	}
    112 	stat.Length = length
    113 	stat.Name = fmt.Sprintf("%d", f.id)
    114 	stat.Uid = "kenji"
    115 	stat.Gid = "kenji"
    116 	stat.Muid = "kenji"
    117 	return &lib9p.FileInfo{Stat: stat}, nil
    118 }
    119 
    120 func (f *numFile) Qid() lib9p.Qid {
    121 	var qid lib9p.Qid
    122 	if f.id == -1 {
    123 		qid = lib9p.Qid{
    124 			Type: lib9p.QTDIR,
    125 			Vers: 0,
    126 			Path: ^uint64(0),
    127 		}
    128 	} else {
    129 		qid = lib9p.Qid{
    130 			Type: lib9p.QTFILE,
    131 			Vers: 0,
    132 			Path: uint64(f.id),
    133 		}
    134 	}
    135 	return qid
    136 }
    137 
    138 func (f *numFile) Read(p []byte) (int, error) {
    139 	if f.id == -1 {
    140 		return 0, fmt.Errorf("is a directory")
    141 	}
    142 	return f.reader.Read(p)
    143 }
    144 
    145 func (f *numFile) ReadAt(p []byte, off int64) (n int, err error) {
    146 	if f.id == -1 {
    147 		return 0, fmt.Errorf("is a directory")
    148 	}
    149 	return f.reader.ReadAt(p, off)
    150 }
    151 
    152 func (f *numFile) ReadDir(n int) ([]fs.DirEntry, error) {
    153 	if f.id != -1 {
    154 		return nil, fmt.Errorf("not a directory")
    155 	}
    156 	de := make([]fs.DirEntry, len(f.children))
    157 	for i, c := range f.children {
    158 		s, err := c.Stat()
    159 		if err != nil {
    160 			return nil, fmt.Errorf("stat: %v", err)
    161 		}
    162 		de[i] = s
    163 	}
    164 	return de, nil
    165 }
    166 
    167 func (f *numFile) Close() error {
    168 	if f.reader != nil {
    169 		f.reader.Seek(0, io.SeekStart)
    170 	}
    171 	return nil
    172 }
    173 
    174 var dFlag = flag.Bool("D", false, "Prints chatty message to the stderr.")
    175 
    176 func main() {
    177 	flag.Parse()
    178 
    179 	if flag.NArg() != 0 {
    180 		fmt.Fprintf(os.Stderr, "usage: %s [-D]\n", os.Args[0])
    181 		os.Exit(1)
    182 	}
    183 
    184 	fsys := new(numFS)
    185 	fsys.root = &numFile{
    186 		fs:     fsys,
    187 		id:     -1,
    188 		reader: nil,
    189 		children: []*numFile{
    190 			&numFile{fsys, 0, bytes.NewReader([]byte("0\n")), nil},
    191 			&numFile{fsys, 1, bytes.NewReader([]byte("1\n")), nil},
    192 			&numFile{fsys, 2, bytes.NewReader([]byte("2\n")), nil},
    193 			&numFile{fsys, 3, bytes.NewReader([]byte("3\n")), nil},
    194 		},
    195 	}
    196 
    197 	listener, err := net.Listen("tcp", "127.0.0.1:5640")
    198 	if err != nil {
    199 		log.Fatalf("listen tcp: %v", err)
    200 	}
    201 	s := lib9p.NewServer(fsys)
    202 	if *dFlag {
    203 		s.Chatty()
    204 	}
    205 	for {
    206 		conn, err := listener.Accept()
    207 		if err != nil {
    208 			log.Printf("accept connection: %v", err)
    209 			continue
    210 		}
    211 		go func() {
    212 			defer conn.Close()
    213 			s.Serve(context.TODO(), conn, conn)
    214 		}()
    215 	}
    216 }