commit 70eee120b67ee810ebb1ac82ce87e998f9f399b3
parent 15b4cc60a88211b9b2add737de049c3c9d7fa044
Author: Matsuda Kenji <info@mtkn.jp>
Date: Tue, 29 Aug 2023 11:03:46 +0900
divide diskfs
Diffstat:
| M | cmd/disk.go | | | 6 | +++--- |
| D | disk_unix.go | | | 151 | ------------------------------------------------------------------------------ |
| A | diskfs/diskfs.go | | | 32 | ++++++++++++++++++++++++++++++++ |
| A | diskfs/file.go | | | 195 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | diskfs/qid_unix.go | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | fcall.go | | | 20 | ++++++++++---------- |
| M | file.go | | | 178 | ++++++++++++++++++++++++++++++++++++------------------------------------------- |
| M | fs.go | | | 30 | +++++++----------------------- |
| M | qid.go | | | 29 | +++++++++++++++-------------- |
| D | qid_plan9.go | | | 2 | -- |
| D | qid_unix.go | | | 84 | ------------------------------------------------------------------------------- |
| M | server.go | | | 53 | +++++++++++++++++++++++++---------------------------- |
| D | time_unix.go | | | 26 | -------------------------- |
| D | uid_unix.go | | | 44 | -------------------------------------------- |
14 files changed, 442 insertions(+), 481 deletions(-)
diff --git a/cmd/disk.go b/cmd/disk.go
@@ -4,12 +4,12 @@ package main
import (
"flag"
"fmt"
- "io/fs"
"log"
"net"
"os"
"lib9p"
+ "lib9p/diskfs"
)
var dFlag = flag.Bool("D", false, "Prints chatty message to the stderr.")
@@ -36,12 +36,12 @@ func main() {
log.Printf("accept connection: %v", err)
continue
}
- disk := os.DirFS(flag.Arg(0))
+ disk := diskfs.Open(flag.Arg(0))
go handle(conn, disk)
}
}
-func handle(conn net.Conn, disk fs.FS) {
+func handle(conn net.Conn, disk *diskfs.FS) {
srv := lib9p.NewServer(disk, 8*1024, conn, conn)
srv.Serve()
}
diff --git a/disk_unix.go b/disk_unix.go
@@ -1,151 +0,0 @@
-package lib9p
-
-import (
- "fmt"
- "log"
- "io"
- "io/fs"
- "path"
-)
-
-type DiskFile struct {
- fs *FS // file system to which this file belongs
- file fs.File // underlying file
- path string // absolute path from the root of the fs.
-}
-
-func openFile(fsys *FS, fpath string) (File, error) {
- file, err := fsys.fs.Open(fpath)
- if err != nil {
- return nil, fmt.Errorf("open fs: %v", err)
- }
- f := &DiskFile{
- fs: fsys,
- file: file,
- path: fpath,
- }
- return f, nil
-}
-
-func (f *DiskFile) pathName() string { return f.path }
-func (f *DiskFile) t() uint16 { return 0 }
-func (f *DiskFile) dev() uint32 { return 0 }
-func (f *DiskFile) length() int64 {
- fi, err := f.file.Stat()
- if err != nil {
- log.Printf("stat: %v", err)
- return 0
- }
- return fi.Size()
-}
-func (f *DiskFile) mode() FileMode {
- fi, err := f.Stat()
- if err != nil {
- log.Printf("stat: %v", err)
- return 0
- }
- return fi.Sys().(*stat).mode
-}
-func (f *DiskFile) name() string {
- fi, err := f.Stat()
- if err != nil {
- log.Printf("stat: %v", err)
- return ""
- }
- return fi.Name()
-}
-
-func (f *DiskFile) Stat() (fs.FileInfo, error) {
- fsfi, err := f.file.Stat()
- if err != nil {
- return nil, fmt.Errorf("stat file: %v, %v", f, err)
- }
- qid := f.qid()
- uid := f.uid()
- gid := f.gid()
- muid := f.muid()
-
- fi := &fileStat{
- info: fsfi,
- stat: &stat{
- qid: &qid,
- name: fsfi.Name(),
- mode: fsModeTo9Mode(fsfi.Mode()),
- aTime: uint32(fsfi.ModTime().Unix()),
- mTime: uint32(fsfi.ModTime().Unix()),
- length: fsfi.Size(),
- uid: uid, // TODO: uid, gid, muid
- gid: gid,
- muid: muid,
- },
- }
- return fi, nil
-}
-
-func (f *DiskFile) Close() error {
- return f.file.Close()
-}
-
-func (f *DiskFile) Read(b []byte) (int, error) {
- return f.file.Read(b)
-}
-
-func (f *DiskFile) ReadAt(p []byte, off int64) (int, error) {
- if f, ok := f.file.(io.ReaderAt); ok {
- return f.ReadAt(p, off)
- }
- file := f.file
-
- buf := make([]byte, 8*1024) // TODO: set appropreate size
- var n int64
- for n+int64(len(buf)) < off {
- m, err := file.Read(buf)
- if err != nil {
- return 0, err
- }
- n += int64(m)
- }
- m, err := file.Read(buf[:off-n])
- if err != nil {
- return 0, err
- }
- n += int64(m)
- if n != off {
- panic("wrong offset")
- }
- return file.Read(p)
-}
-
-func (f *DiskFile) ReadDir(n int) ([]*DirEntry, error) {
- fi, err := f.file.Stat()
- if err != nil {
- return nil, fmt.Errorf("stat: %v", err)
- }
- dir, ok := f.file.(fs.ReadDirFile)
- if !ok || !fi.IsDir() {
- return nil, fmt.Errorf("not a directory")
- }
- fsde, err := dir.ReadDir(n)
- if err != nil {
- return nil, err
- }
- de := make([]*DirEntry, len(fsde))
- for i := 0; i < len(de); i++ {
- fpath := path.Join(f.path, fsde[i].Name())
- file, err := f.fs.Open(fpath)
- if err != nil {
- return nil, fmt.Errorf("open file: %v", err)
- }
- // BUG: TODO: use fsde.Info()
- info, err := file.Stat()
- if err != nil {
- return nil, fmt.Errorf("stat: %v", err)
- }
- de[i] = &DirEntry{
- dirEnt: fsde[i],
- info: info.(*fileStat),
- file: file.(File),
- }
- }
- return de, nil
-}
diff --git a/diskfs/diskfs.go b/diskfs/diskfs.go
@@ -0,0 +1,32 @@
+package diskfs
+
+import (
+ "io/fs"
+ "os"
+
+ "lib9p"
+)
+
+/*
+DiskFS is a file system opened by OpenDiskFS
+*/
+type FS struct {
+ fs fs.FS
+ qidPool *QidPool
+}
+
+func Open(name string) *FS {
+ fsys := os.DirFS(name)
+ return &FS{
+ fs: fsys,
+ qidPool: allocQidPool(),
+ }
+}
+
+func (fsys *FS) Open(name string) (lib9p.File, error) {
+ file, err := openFile(fsys, name)
+ if err != nil {
+ return nil, err
+ }
+ return file, nil
+}
diff --git a/diskfs/file.go b/diskfs/file.go
@@ -0,0 +1,195 @@
+package diskfs
+
+import (
+ "fmt"
+ "io/fs"
+ "log"
+ "os"
+ "os/user"
+ "path"
+ "strconv"
+ "syscall"
+
+ "lib9p"
+)
+
+type File struct {
+ fs *FS // file system to which this file belongs
+ file *os.File // underlying file
+ path string // absolute path from the root of the fs.
+}
+
+func openFile(fsys *FS, fpath string) (*File, error) {
+ file, err := fsys.fs.Open(fpath)
+ if err != nil {
+ return nil, fmt.Errorf("open fs: %v", err)
+ }
+ f := &File{
+ fs: fsys,
+ file: file.(*os.File),
+ path: fpath,
+ }
+ return f, nil
+}
+
+func (f *File) PathName() string { return f.path }
+func (f *File) Type() uint16 { return 0 }
+func (f *File) Dev() uint32 { return 0 }
+
+func (f *File) Qid() lib9p.Qid {
+ qid, ok := f.fs.qidPool.lookup(f)
+ if ok {
+ return qid
+ }
+ qid, err := f.fs.qidPool.alloc(f)
+ if err != nil {
+ panic(fmt.Errorf("alloc qid: %v", err))
+ return lib9p.Qid{}
+ }
+ return qid
+}
+
+func (f *File) Length() int64 {
+ fi, err := f.file.Stat()
+ if err != nil {
+ log.Printf("stat: %v", err)
+ return 0
+ }
+ return fi.Size()
+}
+func (f *File) Mode() lib9p.FileMode {
+ fi, err := f.Stat()
+ if err != nil {
+ log.Printf("stat: %v", err)
+ return 0
+ }
+ return fi.Sys().(*lib9p.Stat).Mode
+}
+func (f *File) Name() string {
+ fi, err := f.Stat()
+ if err != nil {
+ log.Printf("stat: %v", err)
+ return ""
+ }
+ return fi.Name()
+}
+
+func (f *File) Atime() uint32 {
+ fi, err := f.file.Stat()
+ if err != nil {
+ log.Printf("stat error: %v", err)
+ return 0 // TODO: error check?
+ }
+ sys := fi.Sys()
+ return uint32(sys.(syscall.Stat_t).Atim.Sec)
+}
+
+func (f *File) Mtime() uint32 {
+ fi, err := f.file.Stat()
+ if err != nil {
+ log.Printf("stat error: %v", err)
+ return 0 // TODO: error check?
+ }
+ sys := fi.Sys()
+ return uint32(sys.(syscall.Stat_t).Mtim.Sec)
+}
+
+func (f *File) Uid() string {
+ info, err := f.file.Stat()
+ if err != nil {
+ log.Printf("stat %v: %v", f, err)
+ return ""
+ }
+ uid := info.Sys().(*syscall.Stat_t).Uid
+ user, err := user.LookupId(strconv.Itoa(int(uid)))
+ if err != nil {
+ log.Printf("LookupId(%d): %v", uid, err)
+ return ""
+ }
+ return user.Username
+}
+
+func (f *File) Gid() string {
+ info, err := f.file.Stat()
+ if err != nil {
+ log.Printf("stat %v: %v", f, err)
+ return ""
+ }
+ gid := info.Sys().(*syscall.Stat_t).Gid
+ group, err := user.LookupGroupId(strconv.Itoa(int(gid)))
+ if err != nil {
+ log.Printf("LookupGroupId(%d): %v", gid, err)
+ return ""
+ }
+ return group.Name
+}
+
+func (f *File) Muid() string {
+ log.Printf("muid not implemented")
+ return ""
+}
+
+func (f *File) Stat() (fs.FileInfo, error) {
+ fsfi, err := f.file.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("stat file: %v, %v", f, err)
+ }
+ qid := f.Qid()
+ uid := f.Uid()
+ gid := f.Gid()
+ muid := f.Muid()
+
+ fi := &lib9p.FileInfo{
+ Info: fsfi,
+ Stat: &lib9p.Stat{
+ Qid: &qid,
+ Name: fsfi.Name(),
+ Mode: lib9p.FSModeTo9Mode(fsfi.Mode()),
+ Atime: uint32(fsfi.ModTime().Unix()),
+ Mtime: uint32(fsfi.ModTime().Unix()),
+ Length: fsfi.Size(),
+ Uid: uid,
+ Gid: gid,
+ Muid: muid,
+ },
+ }
+ return fi, nil
+}
+
+func (f *File) Close() error {
+ return f.file.Close()
+}
+
+func (f *File) Read(b []byte) (int, error) {
+ return f.file.Read(b)
+}
+
+func (f *File) ReadAt(p []byte, off int64) (int, error) {
+ return f.file.ReadAt(p, off)
+}
+
+func (f *File) ReadDir(n int) ([]*lib9p.DirEntry, error) {
+ fsde, err := f.file.ReadDir(n)
+ if err != nil {
+ return nil, err
+ }
+ de := make([]*lib9p.DirEntry, len(fsde))
+ for i := 0; i < len(de); i++ {
+ fpath := path.Join(f.path, fsde[i].Name())
+ file, err := f.fs.Open(fpath)
+ if err != nil {
+ return nil, fmt.Errorf("open file: %v", err)
+ }
+ // BUG: TODO: use fsde.Info()
+ info, err := file.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("stat: %v", err)
+ }
+ de[i] = &lib9p.DirEntry{
+ DirEnt: fsde[i],
+ FileInfo: info.(*lib9p.FileInfo),
+ File: file.(*File),
+ }
+ }
+ return de, nil
+}
diff --git a/diskfs/qid_unix.go b/diskfs/qid_unix.go
@@ -0,0 +1,72 @@
+package diskfs
+
+import (
+ "fmt"
+ "syscall"
+
+ "lib9p"
+)
+
+type fileID struct {
+ device uint64
+ inode uint64
+}
+
+type QidPool struct {
+ m map[fileID]lib9p.Qid
+ nextQid uint64
+}
+
+func (f *File) id() (fileID, error) {
+ fi, err := f.file.Stat()
+ if err != nil {
+ return fileID{}, err
+ }
+ sys := fi.Sys().(*syscall.Stat_t)
+ id := fileID{
+ device: sys.Dev,
+ inode: sys.Ino,
+ }
+ return id, nil
+}
+
+func allocQidPool() *QidPool {
+ return &QidPool{
+ m: make(map[fileID]lib9p.Qid),
+ }
+}
+
+func (pool *QidPool) lookup(f *File) (lib9p.Qid, bool) {
+ id, err := f.id()
+ if err != nil {
+ return lib9p.Qid{}, false
+ }
+ qid, ok := pool.m[id]
+ return qid, ok
+}
+
+func (pool *QidPool) alloc(f *File) (lib9p.Qid, error) {
+ id, err := f.id()
+ if err != nil {
+ return lib9p.Qid{}, fmt.Errorf("get id: %v", err)
+ }
+ fi, err := f.file.Stat()
+ if err != nil {
+ return lib9p.Qid{}, fmt.Errorf("stat %v: %v", f, err)
+ }
+ qtype := lib9p.FSModeToQidType(fi.Mode())
+ qid := lib9p.Qid{
+ Path: pool.nextQid,
+ Type: qtype,
+ }
+ pool.m[id] = qid
+ return qid, nil
+}
+
+func (pool *QidPool) delete(f *File) {
+ id, err := f.id()
+ if err != nil {
+ return
+ }
+ delete(pool.m, id)
+}
+\ No newline at end of file
diff --git a/fcall.go b/fcall.go
@@ -33,8 +33,8 @@ const (
Rremove = 123
Tstat = 124
Rstat = 125
- Twstat = 126
- Rwstat = 127
+ TwStat = 126
+ RwStat = 127
Tmax = 128
)
@@ -823,16 +823,16 @@ func (msg *TStat) String() string {
type RStat struct {
tag uint16
- info *fileStat
+ info *FileInfo
}
func newRStat(buf []byte) *RStat { panic("not implemented") }
func (msg *RStat) Size() uint32 {
- stat, ok := msg.info.Sys().(*stat)
+ Stat, ok := msg.info.Sys().(*Stat)
if !ok {
- panic("not stat")
+ panic("not Stat")
}
- return uint32(4 + 1 + 2 + 2 + 2 + stat.size())
+ return uint32(4 + 1 + 2 + 2 + 2 + Stat.size())
}
func (msg *RStat) Type() MsgType { return Rstat }
func (msg *RStat) Tag() uint16 { return msg.tag }
@@ -841,11 +841,11 @@ func (msg *RStat) marshal() []byte {
pbit32(buf[0:4], msg.Size())
buf[4] = uint8(Rstat)
pbit16(buf[5:7], msg.Tag())
- stat, ok := msg.info.Sys().(*stat)
+ Stat, ok := msg.info.Sys().(*Stat)
if !ok {
- panic("not stat")
+ panic("not Stat")
}
- fiBuf := stat.marshal()
+ fiBuf := Stat.marshal()
pbit16(buf[7:9], uint16(len(fiBuf)))
for i := 0; i < len(fiBuf); i++ {
buf[9+i] = fiBuf[i]
@@ -854,5 +854,5 @@ func (msg *RStat) marshal() []byte {
}
func (msg *RStat) String() string {
- return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.info.stat)
+ return fmt.Sprintf("Rstat tag %d Stat %s", msg.Tag(), msg.info.Stat)
}
diff --git a/file.go b/file.go
@@ -3,7 +3,7 @@ package lib9p
import (
"fmt"
"io/fs"
- "os"
+// "os"
"time"
)
@@ -25,24 +25,24 @@ const (
func hasPerm(f File, uid string, p fs.FileMode) (bool, error) {
fi, err := f.Stat()
if err != nil {
- return false, fmt.Errorf("stat: %v", err)
+ return false, fmt.Errorf("Stat: %v", err)
}
fp := fi.Mode().Perm()
- stat, ok := fi.Sys().(*stat)
+ Stat, ok := fi.Sys().(*Stat)
if !ok {
- panic("not stat")
+ panic("not Stat")
}
m := fp & 7 // other
if (p & m) == p {
return true, nil
}
- if stat.uid == uid {
+ if Stat.Uid == uid {
m |= (fp >> 6) & 7
if (p & m) == p {
return true, nil
}
}
- if stat.gid == uid {
+ if Stat.Gid == uid {
m |= (fp >> 3) & 7
if (p & m) == p {
return true, nil
@@ -51,77 +51,77 @@ func hasPerm(f File, uid string, p fs.FileMode) (bool, error) {
return false, nil
}
-type stat struct {
- t uint16
- dev uint32
- qid *Qid
- mode FileMode
- aTime uint32
- mTime uint32
- length int64
- name string
- uid string
- gid string
- muid string
+type Stat struct {
+ Type uint16
+ Dev uint32
+ Qid *Qid
+ Mode FileMode
+ Atime uint32
+ Mtime uint32
+ Length int64
+ Name string
+ Uid string
+ Gid string
+ Muid string
}
-func (s *stat) size() uint16 {
+func (s *Stat) size() uint16 {
return uint16(2 + 4 + 13 + 4 + 4 + 4 + 8 +
// type + dev + qid + mode + atime + mtime + length
- 2 + len(s.name) +
- 2 + len(s.uid) +
- 2 + len(s.gid) +
- 2 + len(s.muid))
+ 2 + len(s.Name) +
+ 2 + len(s.Uid) +
+ 2 + len(s.Gid) +
+ 2 + len(s.Muid))
}
-func (s *stat) marshal() []byte {
+func (s *Stat) marshal() []byte {
cur := 0
size := s.size()
msg := make([]byte, 2+size)
pbit16(msg[cur:cur+2], size)
cur += 2
- pbit16(msg[cur:cur+2], s.t)
+ pbit16(msg[cur:cur+2], s.Type)
cur += 2
- pbit32(msg[cur:cur+4], s.dev)
+ pbit32(msg[cur:cur+4], s.Dev)
cur += 4
- msg[cur] = uint8(s.qid.Type())
+ msg[cur] = uint8(s.Qid.Type)
cur += 1
- pbit32(msg[cur:cur+4], s.qid.Vers())
+ pbit32(msg[cur:cur+4], s.Qid.Vers)
cur += 4
- pbit64(msg[cur:cur+8], s.qid.Path())
+ pbit64(msg[cur:cur+8], s.Qid.Path)
cur += 8
- pbit32(msg[cur:cur+4], uint32(s.mode))
+ pbit32(msg[cur:cur+4], uint32(s.Mode))
cur += 4
- pbit32(msg[cur:cur+4], s.aTime)
+ pbit32(msg[cur:cur+4], s.Atime)
cur += 4
- pbit32(msg[cur:cur+4], s.mTime)
+ pbit32(msg[cur:cur+4], s.Mtime)
cur += 4
- pbit64(msg[cur:cur+8], uint64(s.length))
+ pbit64(msg[cur:cur+8], uint64(s.Length))
cur += 8
- pbit16(msg[cur:cur+2], uint16(len(s.name)))
+ pbit16(msg[cur:cur+2], uint16(len(s.Name)))
cur += 2
- for i := 0; i < len(s.name); i++ {
- msg[cur+i] = s.name[i]
+ for i := 0; i < len(s.Name); i++ {
+ msg[cur+i] = s.Name[i]
}
- cur += len(s.name)
- pbit16(msg[cur:cur+2], uint16(len(s.uid)))
+ cur += len(s.Name)
+ pbit16(msg[cur:cur+2], uint16(len(s.Uid)))
cur += 2
- for i := 0; i < len(s.uid); i++ {
- msg[cur+i] = s.uid[i]
+ for i := 0; i < len(s.Uid); i++ {
+ msg[cur+i] = s.Uid[i]
}
- cur += len(s.uid)
- pbit16(msg[cur:cur+2], uint16(len(s.gid)))
+ cur += len(s.Uid)
+ pbit16(msg[cur:cur+2], uint16(len(s.Gid)))
cur += 2
- for i := 0; i < len(s.gid); i++ {
- msg[cur+i] = s.gid[i]
+ for i := 0; i < len(s.Gid); i++ {
+ msg[cur+i] = s.Gid[i]
}
- cur += len(s.gid)
- pbit16(msg[cur:cur+2], uint16(len(s.muid)))
+ cur += len(s.Gid)
+ pbit16(msg[cur:cur+2], uint16(len(s.Muid)))
cur += 2
- for i := 0; i < len(s.muid); i++ {
- msg[cur+i] = s.muid[i]
+ for i := 0; i < len(s.Muid); i++ {
+ msg[cur+i] = s.Muid[i]
}
- cur += len(s.muid)
+ cur += len(s.Muid)
if len(msg) != cur {
panic(fmt.Errorf("cursor position %d and msg length %d don't match",
@@ -130,44 +130,44 @@ func (s *stat) marshal() []byte {
return msg
}
-func (s *stat) String() string {
+func (s *Stat) String() string {
return fmt.Sprintf("'%s' '%s' '%s' '%s' q %v m %#o at %d mt %d l %d t %d d %d",
- s.name, s.uid, s.gid, s.muid, s.qid, s.mode,
- s.aTime, s.mTime, s.length, s.t, s.dev)
+ s.Name, s.Uid, s.Gid, s.Muid, s.Qid, s.Mode,
+ s.Atime, s.Mtime, s.Length, s.Type, s.Dev)
}
/*
fs.FileInfo
*/
-type fileStat struct {
- info fs.FileInfo
- stat *stat
+type FileInfo struct {
+ Info fs.FileInfo
+ Stat *Stat
}
-func (fi *fileStat) Name() string { return fi.info.Name() }
-func (fi *fileStat) Size() int64 { return fi.info.Size() }
-func (fi *fileStat) Mode() fs.FileMode { return fi.info.Mode() }
-func (fi *fileStat) ModTime() time.Time { return fi.info.ModTime() }
-func (fi *fileStat) IsDir() bool { return fi.info.IsDir() }
-func (fi *fileStat) Sys() any { return fi.stat }
-func (fi *fileStat) Qid() *Qid { return fi.Sys().(*stat).qid }
+func (fi *FileInfo) Name() string { return fi.Info.Name() }
+func (fi *FileInfo) Size() int64 { return fi.Info.Size() }
+func (fi *FileInfo) Mode() fs.FileMode { return fi.Info.Mode() }
+func (fi *FileInfo) ModTime() time.Time { return fi.Info.ModTime() }
+func (fi *FileInfo) IsDir() bool { return fi.Info.IsDir() }
+func (fi *FileInfo) Sys() any { return fi.Stat }
+func (fi *FileInfo) Qid() *Qid { return fi.Sys().(*Stat).Qid }
type File interface {
fs.File
- pathName() string
-
- t() uint16
- dev() uint32
- qid() Qid
- mode() FileMode
- atime() uint32
- mtime() uint32
- length() int64
- name() string
- uid() string
- gid() string
- muid() string
+ PathName() string
+
+ Type() uint16
+ Dev() uint32
+ Qid() Qid
+ Mode() FileMode
+ Atime() uint32
+ Mtime() uint32
+ Length() int64
+ Name() string
+ Uid() string
+ Gid() string
+ Muid() string
}
type ReadDirFile interface {
@@ -175,27 +175,13 @@ type ReadDirFile interface {
ReadDir(int) ([]*DirEntry, error)
}
-type hasQid interface {
- Qid() *Qid
-}
-
-func sameFile(fi0, fi1 fs.FileInfo) bool {
- if hq0, ok := fi0.(hasQid); ok {
- if hq1, ok := fi1.(hasQid); ok {
- return hq0.Qid().Path() == hq1.Qid().Path()
- }
- }
- return os.SameFile(fi0, fi1)
-}
-
-
type DirEntry struct {
- dirEnt fs.DirEntry // underlying fs.DirEntry
- info *fileStat
- file File
+ DirEnt fs.DirEntry // underlying fs.DirEntry
+ FileInfo *FileInfo
+ File File
}
-func (e *DirEntry) Name() string { return e.dirEnt.Name() }
-func (e *DirEntry) IsDir() bool { return e.dirEnt.IsDir() }
-func (e *DirEntry) Type() fs.FileMode { return e.dirEnt.Type() }
-func (e *DirEntry) Info() (*fileStat, error) { return e.info, nil }
+func (e *DirEntry) Name() string { return e.DirEnt.Name() }
+func (e *DirEntry) IsDir() bool { return e.DirEnt.IsDir() }
+func (e *DirEntry) Type() fs.FileMode { return e.DirEnt.Type() }
+func (e *DirEntry) Info() (*FileInfo, error) { return e.FileInfo, nil }
diff --git a/fs.go b/fs.go
@@ -5,23 +5,14 @@ import (
"path"
)
-type FS struct {
- fs fs.FS // underlying file system
- qidPool *QidPool
-}
-
/*
- Returned file must implement File
+ Open() must return File with Qid() method.
*/
-func (fsys *FS) Open(name string) (fs.File, error) {
- file, err := openFile(fsys, name)
- if err != nil {
- return nil, err
- }
- return file, nil
+type FS interface {
+ Open(string) (File, error)
}
-func (fsys *FS) walk(root string, wnames []string) ([]*Qid, error) {
+func walk(fsys FS, root string, wnames []string) ([]*Qid, error) {
wqids := make([]*Qid, len(wnames))
curName := root
for i, name := range wnames {
@@ -30,20 +21,13 @@ func (fsys *FS) walk(root string, wnames []string) ([]*Qid, error) {
if err != nil {
return wqids, err
}
-
- qid, ok := fsys.qidPool.lookup(f.(File))
- if !ok {
- qid, err = fsys.qidPool.alloc(f.(File))
- if err != nil {
- return wqids, err
- }
- }
+ qid := f.Qid()
wqids[i] = &qid
}
return wqids, nil
}
-func fsModeToQidType(fm fs.FileMode) QidType {
+func FSModeToQidType(fm fs.FileMode) QidType {
var qt QidType
if fm&fs.ModeDir != 0 {
qt |= QTDIR
@@ -67,7 +51,7 @@ func fsModeToQidType(fm fs.FileMode) QidType {
return qt
}
-func fsModeTo9Mode(mode fs.FileMode) FileMode {
+func FSModeTo9Mode(mode fs.FileMode) FileMode {
mode9 := FileMode(mode & fs.ModePerm)
if mode&fs.ModeDir != 0 {
mode9 |= DMDIR
diff --git a/qid.go b/qid.go
@@ -19,39 +19,42 @@ const (
)
type Qid struct {
- t QidType
- vers uint32
- path uint64
+ Type QidType
+ Vers uint32
+ Path uint64
}
func newQid(b []byte) *Qid {
return &Qid{
- t: QidType(b[0]),
- vers: gbit32(b[1:5]),
- path: gbit64(b[5:13]),
+ Type: QidType(b[0]),
+ Vers: gbit32(b[1:5]),
+ Path: gbit64(b[5:13]),
}
}
-func (q *Qid) Type() QidType { return q.t }
+/*
+func (q *Qid) Type() QidType { return q.Type }
func (q *Qid) SetType(t QidType) { q.t = t }
func (q *Qid) Vers() uint32 { return q.vers }
func (q *Qid) SetVers(v uint32) { q.vers = v }
func (q *Qid) Path() uint64 { return q.path }
func (q *Qid) SetPath(p uint64) { q.path = p }
+*/
+
func (q *Qid) marshal() []byte {
buf := make([]byte, 13)
- buf[0] = uint8(q.t)
- pbit32(buf[1:5], q.vers)
- pbit64(buf[5:13], q.path)
+ buf[0] = uint8(q.Type)
+ pbit32(buf[1:5], q.Vers)
+ pbit64(buf[5:13], q.Path)
return buf
}
func (q *Qid) String() string {
- return fmt.Sprintf("(%016d %d %s)", q.Path(), q.Vers(), q.typeStr())
+ return fmt.Sprintf("(%016d %d %s)", q.Path, q.Vers, q.typeStr())
}
// TypeStr returns the q.Type() as string for debugging information.
func (q *Qid) typeStr() string {
var s string
- t := q.Type()
+ t := q.Type
if t&QTDIR != 0 {
s += "d"
}
@@ -66,5 +69,3 @@ func (q *Qid) typeStr() string {
}
return s
}
-
-
diff --git a/qid_plan9.go b/qid_plan9.go
@@ -1 +0,0 @@
-package lib9p
-\ No newline at end of file
diff --git a/qid_unix.go b/qid_unix.go
@@ -1,83 +0,0 @@
-package lib9p
-
-import (
- "fmt"
- "syscall"
-)
-
-type fileID struct {
- device uint64
- inode uint64
-}
-
-type QidPool struct {
- m map[fileID]Qid
- nextQid uint64
-}
-
-func (f *DiskFile) id() (fileID, error) {
- fi, err := f.file.Stat()
- if err != nil {
- return fileID{}, err
- }
- sys := fi.Sys().(*syscall.Stat_t)
- id := fileID{
- device: sys.Dev,
- inode: sys.Ino,
- }
- return id, nil
-}
-
-func (f *DiskFile) qid() Qid {
- qid, ok := f.fs.qidPool.lookup(f)
- if ok {
- return qid
- }
- qid, err := f.fs.qidPool.alloc(f)
- if err != nil {
- panic(fmt.Errorf("alloc qid: %v", err))
- return Qid{}
- }
- return qid
-}
-
-func allocQidPool() *QidPool {
- return &QidPool{
- m: make(map[fileID]Qid),
- }
-}
-
-func (pool *QidPool) lookup(f File) (Qid, bool) {
- id, err := f.(*DiskFile).id()
- if err != nil {
- return Qid{}, false
- }
- qid, ok := pool.m[id]
- return qid, ok
-}
-
-func (pool *QidPool) alloc(f File) (Qid, error) {
- id, err := f.(*DiskFile).id()
- if err != nil {
- return Qid{}, fmt.Errorf("get id: %v", err)
- }
- fi, err := f.(*DiskFile).file.Stat()
- if err != nil {
- return Qid{}, fmt.Errorf("stat %v: %v", f, err)
- }
- qtype := fsModeToQidType(fi.Mode())
- qid := Qid{
- path: pool.nextQid,
- t: qtype,
- }
- pool.m[id] = qid
- return qid, nil
-}
-
-func (pool *QidPool) delete(f File) {
- id, err := f.(*DiskFile).id()
- if err != nil {
- return
- }
- delete(pool.m, id)
-}
-\ No newline at end of file
diff --git a/server.go b/server.go
@@ -19,7 +19,7 @@ func Chatty() {
var EDupTag = fmt.Errorf("duplicate tag")
type Server struct {
- fs *FS
+ fs FS
MSize uint32
fPool *FidPool
rPool *ReqPool
@@ -27,18 +27,15 @@ type Server struct {
Writer io.Writer
}
-func NewServer(fsys fs.FS, mSize uint32, r io.Reader, w io.Writer) *Server {
- s := new(Server)
- s.fs = &FS{
- fs: fsys,
- qidPool: allocQidPool(),
- }
- s.MSize = mSize
- s.fPool = allocFidPool()
- s.rPool = allocReqPool()
- s.Reader = r
- s.Writer = w
- return s
+func NewServer(fsys FS, mSize uint32, r io.Reader, w io.Writer) *Server {
+ return &Server{
+ fs: fsys,
+ MSize: mSize,
+ fPool: allocFidPool(),
+ rPool: allocReqPool(),
+ Reader: r,
+ Writer: w,
+ }
}
func (s *Server) getReq() (*Req, error) {
@@ -143,12 +140,12 @@ func sAttach(s *Server, r *Req) {
fid.OMode = OREAD
info, err := fid.File.Stat()
if err != nil {
- log.Printf("stat %s, %v", fid.File, err)
+ log.Printf("Stat %s, %v", fid.File, err)
respond(r, fmt.Errorf("internal error"))
return
}
- stat := info.Sys().(*stat)
- fid.Qid = stat.qid
+ Stat := info.Sys().(*Stat)
+ fid.Qid = Stat.Qid
ofcall := &RAttach{
tag: ifcall.Tag(),
@@ -180,7 +177,7 @@ func sWalk(s *Server, r *Req) {
return
}
- wqids, err := s.fs.walk(oldFid.File.pathName(), ifcall.WName())
+ wqids, err := walk(s.fs, oldFid.File.PathName(), ifcall.WName())
if err != nil {
s.fPool.delete(ifcall.NewFid())
log.Printf("walk fs: %v", err)
@@ -189,7 +186,7 @@ func sWalk(s *Server, r *Req) {
}
relPath := path.Join(ifcall.WName()...)
- absPath := path.Join(oldFid.File.pathName(), relPath)
+ absPath := path.Join(oldFid.File.PathName(), relPath)
f, err := s.fs.Open(absPath)
if err != nil {
log.Printf("open root dir: %v", err)
@@ -201,12 +198,12 @@ func sWalk(s *Server, r *Req) {
newFid.Uid = oldFid.Uid
info, err := newFid.File.Stat()
if err != nil {
- log.Printf("stat %v, %v", newFid.File, err)
+ log.Printf("Stat %v, %v", newFid.File, err)
respond(r, fmt.Errorf("internal error"))
return
}
- stat := info.Sys().(*stat)
- newFid.Qid = stat.qid
+ Stat := info.Sys().(*Stat)
+ newFid.Qid = Stat.Qid
ofcall := &RWalk{
tag: r.ifcall.Tag(),
@@ -231,9 +228,9 @@ func sOpen(s *Server, r *Req) {
respond(r, fmt.Errorf("already open"))
return
}
- // TODO: this if statement is from plan9's lib9p.
+ // TODO: this if Statement is from plan9's lib9p.
// I don't understand this.
- if fidStruct.Qid.t == QTDIR && ifcall.Mode() & ^ORCLOSE != OREAD {
+ if fidStruct.Qid.Type == QTDIR && ifcall.Mode() & ^ORCLOSE != OREAD {
respond(r, fmt.Errorf("is a directory"))
return
}
@@ -254,7 +251,7 @@ func sOpen(s *Server, r *Req) {
if ifcall.Mode()&OTRUNC != 0 {
p |= AWRITE
}
- if fidStruct.Qid.t&QTDIR != 0 && p != AREAD {
+ if fidStruct.Qid.Type&QTDIR != 0 && p != AREAD {
respond(r, fmt.Errorf("permission denied"))
return
}
@@ -307,7 +304,7 @@ func sRead(s *Server, r *Req) {
var err error
fi, err := fid.File.Stat()
if err != nil {
- log.Printf("stat: %v")
+ log.Printf("Stat: %v")
respond(r, fmt.Errorf("internal error"))
return
}
@@ -323,7 +320,7 @@ func sRead(s *Server, r *Req) {
log.Printf("info: %v", err)
continue
}
- st := info.Sys().(*stat)
+ st := info.Sys().(*Stat)
buf := st.marshal()
if n+len(buf) > len(data) {
break
@@ -385,14 +382,14 @@ func sStat(s *Server, r *Req) {
}
fileInfo, err := fidStruct.File.Stat()
if err != nil {
- log.Printf("stat file %v: %v", fidStruct.File, err)
+ log.Printf("Stat file %v: %v", fidStruct.File, err)
respond(r, fmt.Errorf("internal error"))
return
}
ofcall := &RStat{
tag: ifcall.Tag(),
- info: fileInfo.(*fileStat),
+ info: fileInfo.(*FileInfo),
}
r.ofcall = ofcall
diff --git a/time_unix.go b/time_unix.go
@@ -1,26 +0,0 @@
-package lib9p
-
-import (
- "log"
- "syscall"
-)
-
-func (f *DiskFile) atime() uint32 {
- fi, err := f.file.Stat()
- if err != nil {
- log.Printf("stat error: %v", err)
- return 0 // TODO: error check?
- }
- sys := fi.Sys()
- return uint32(sys.(syscall.Stat_t).Atim.Sec)
-}
-
-func (f *DiskFile) mtime() uint32 {
- fi, err := f.file.Stat()
- if err != nil {
- log.Printf("stat error: %v", err)
- return 0 // TODO: error check?
- }
- sys := fi.Sys()
- return uint32(sys.(syscall.Stat_t).Mtim.Sec)
-}
diff --git a/uid_unix.go b/uid_unix.go
@@ -1,43 +0,0 @@
-package lib9p
-
-import (
- "log"
- "os/user"
- "strconv"
- "syscall"
-)
-
-func (f *DiskFile) uid() string {
- info, err := f.file.Stat()
- if err != nil {
- log.Printf("stat %v: %v", f, err)
- return ""
- }
- uid := info.Sys().(*syscall.Stat_t).Uid
- user, err := user.LookupId(strconv.Itoa(int(uid)))
- if err != nil {
- log.Printf("LookupId(%d): %v", uid, err)
- return ""
- }
- return user.Username
-}
-
-func (f *DiskFile) gid() string {
- info, err := f.file.Stat()
- if err != nil {
- log.Printf("stat %v: %v", f, err)
- return ""
- }
- gid := info.Sys().(*syscall.Stat_t).Gid
- group, err := user.LookupGroupId(strconv.Itoa(int(gid)))
- if err != nil {
- log.Printf("LookupGroupId(%d): %v", gid, err)
- return ""
- }
- return group.Name
-}
-
-func (f *DiskFile) muid() string {
- log.Printf("muid not implemented")
- return ""
-}
-\ No newline at end of file