package main import ( "fmt" "path" "sync" p9 "github.com/Harvey-OS/ninep/protocol" "git.samanthony.xyz/buth/back/auth" ) const ( _ uint64 = iota rootQidPath usersQidPath sessionsQidPath ) type File interface { Qid() (p9.QID, error) // TODO } type Dir interface { File // TODO: walk, create } // Authfs is the root p9.NineServer. type Authfs struct { *RootDir *UsersDir *SessionsDir mu sync.Mutex // guards below files map[p9.FID]File } func NewAuthfs(rootPath string) (*Authfs, error) { root := NewRootDir() users, err := NewUsersDir(rootPath, root.Version) if err != nil { return nil, err } return &Authfs{ root, users, NewSessionsDir(root.Version), sync.Mutex{}, make(map[p9.FID]File), }, nil } func (fs *Authfs) Close() { fs.RootDir.Close() fs.UsersDir.Close() fs.SessionsDir.Close() } func (fs *Authfs) Rattach(fid, afid p9.FID, uname, aname string) (p9.QID, error) { if afid != p9.NOFID { return p9.QID{}, fmt.Errorf("authfs: no authentication required") } var ( f File err error ok bool ) aname = path.Clean(path.Join("/", aname)) dir, file := path.Split(aname) switch dir { case "/": switch file { case "": f = fs.RootDir case "users": f = fs.UsersDir case "sessions": f = fs.SessionsDir default: return p9.QID{}, ErrFileNotExist } case "/users/": f, err = fs.UsersDir.Walk(file) if err != nil { return p9.QID{}, err } case "/sessions/": sessid, err := auth.ParseSessId(file) if err != nil { return p9.QID{}, err } f, ok = fs.SessionsDir.Get(sessid) if !ok { return p9.QID{}, ErrFileNotExist } default: return p9.QID{}, ErrFileNotExist } if f == nil { panic("unreachable") } qid, err := f.Qid() if err != nil { return p9.QID{}, err } if err := fs.attach(fid, f); err != nil { return p9.QID{}, err } return qid, nil } func (fs *Authfs) attach(fid p9.FID, f File) error { fs.mu.Lock() defer fs.mu.Unlock() if _, exists := fs.files[fid]; exists { return ErrFidExist } fs.files[fid] = f return nil }