435 lines
8.0 KiB
Go
435 lines
8.0 KiB
Go
// Copyright 2009 The Go9p Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package go9p
|
|
|
|
import "runtime"
|
|
|
|
func (srv *Srv) version(req *SrvReq) {
|
|
tc := req.Tc
|
|
conn := req.Conn
|
|
|
|
if tc.Msize < IOHDRSZ {
|
|
req.RespondError(&Error{"msize too small", EINVAL})
|
|
return
|
|
}
|
|
|
|
if tc.Msize < conn.Msize {
|
|
conn.Msize = tc.Msize
|
|
}
|
|
|
|
conn.Dotu = tc.Version == "9P2000.u" && srv.Dotu
|
|
ver := "9P2000"
|
|
if conn.Dotu {
|
|
ver = "9P2000.u"
|
|
}
|
|
|
|
/* make sure that the responses of all current requests will be ignored */
|
|
conn.Lock()
|
|
for tag, r := range conn.reqs {
|
|
if tag == NOTAG {
|
|
continue
|
|
}
|
|
|
|
for rr := r; rr != nil; rr = rr.next {
|
|
rr.Lock()
|
|
rr.status |= reqFlush
|
|
rr.Unlock()
|
|
}
|
|
}
|
|
conn.Unlock()
|
|
|
|
req.RespondRversion(conn.Msize, ver)
|
|
}
|
|
|
|
func (srv *Srv) auth(req *SrvReq) {
|
|
tc := req.Tc
|
|
conn := req.Conn
|
|
if tc.Afid == NOFID {
|
|
req.RespondError(Eunknownfid)
|
|
return
|
|
}
|
|
|
|
req.Afid = conn.FidNew(tc.Afid)
|
|
if req.Afid == nil {
|
|
req.RespondError(Einuse)
|
|
return
|
|
}
|
|
|
|
var user User = nil
|
|
if tc.Unamenum != NOUID || conn.Dotu {
|
|
user = srv.Upool.Uid2User(int(tc.Unamenum))
|
|
} else if tc.Uname != "" {
|
|
user = srv.Upool.Uname2User(tc.Uname)
|
|
}
|
|
|
|
if runtime.GOOS != "windows" {
|
|
if user == nil {
|
|
req.RespondError(Enouser)
|
|
return
|
|
}
|
|
}
|
|
|
|
req.Afid.User = user
|
|
req.Afid.Type = QTAUTH
|
|
if aop, ok := (srv.ops).(AuthOps); ok {
|
|
aqid, err := aop.AuthInit(req.Afid, tc.Aname)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
} else {
|
|
aqid.Type |= QTAUTH // just in case
|
|
req.RespondRauth(aqid)
|
|
}
|
|
} else {
|
|
req.RespondError(Enoauth)
|
|
}
|
|
|
|
}
|
|
|
|
func (srv *Srv) authPost(req *SrvReq) {
|
|
if req.Rc != nil && req.Rc.Type == Rauth {
|
|
req.Afid.IncRef()
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) attach(req *SrvReq) {
|
|
tc := req.Tc
|
|
conn := req.Conn
|
|
if tc.Fid == NOFID {
|
|
req.RespondError(Eunknownfid)
|
|
return
|
|
}
|
|
|
|
req.Fid = conn.FidNew(tc.Fid)
|
|
if req.Fid == nil {
|
|
req.RespondError(Einuse)
|
|
return
|
|
}
|
|
|
|
if tc.Afid != NOFID {
|
|
req.Afid = conn.FidGet(tc.Afid)
|
|
if req.Afid == nil {
|
|
req.RespondError(Eunknownfid)
|
|
}
|
|
}
|
|
|
|
var user User = nil
|
|
if tc.Unamenum != NOUID || conn.Dotu {
|
|
user = srv.Upool.Uid2User(int(tc.Unamenum))
|
|
} else if tc.Uname != "" {
|
|
user = srv.Upool.Uname2User(tc.Uname)
|
|
}
|
|
|
|
if runtime.GOOS != "windows" {
|
|
if user == nil {
|
|
req.RespondError(Enouser)
|
|
return
|
|
}
|
|
}
|
|
|
|
req.Fid.User = user
|
|
if aop, ok := (srv.ops).(AuthOps); ok {
|
|
err := aop.AuthCheck(req.Fid, req.Afid, tc.Aname)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
(srv.ops).(SrvReqOps).Attach(req)
|
|
}
|
|
|
|
func (srv *Srv) attachPost(req *SrvReq) {
|
|
if req.Rc != nil && req.Rc.Type == Rattach {
|
|
req.Fid.Type = req.Rc.Qid.Type
|
|
req.Fid.IncRef()
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) flush(req *SrvReq) {
|
|
conn := req.Conn
|
|
tag := req.Tc.Oldtag
|
|
PackRflush(req.Rc)
|
|
conn.Lock()
|
|
r := conn.reqs[tag]
|
|
if r != nil {
|
|
req.flushreq = r.flushreq
|
|
r.flushreq = req
|
|
}
|
|
conn.Unlock()
|
|
|
|
if r == nil {
|
|
// there are no requests with that tag
|
|
req.Respond()
|
|
return
|
|
}
|
|
|
|
r.Lock()
|
|
status := r.status
|
|
if (status & (reqWork | reqSaved)) == 0 {
|
|
/* the request is not worked on yet */
|
|
r.status |= reqFlush
|
|
}
|
|
r.Unlock()
|
|
|
|
if (status & (reqWork | reqSaved)) == 0 {
|
|
r.Respond()
|
|
} else {
|
|
if op, ok := (srv.ops).(FlushOp); ok {
|
|
op.Flush(r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) walk(req *SrvReq) {
|
|
conn := req.Conn
|
|
tc := req.Tc
|
|
fid := req.Fid
|
|
|
|
/* we can't walk regular files, only clone them */
|
|
if len(tc.Wname) > 0 && (fid.Type&QTDIR) == 0 {
|
|
req.RespondError(Enotdir)
|
|
return
|
|
}
|
|
|
|
/* we can't walk open files */
|
|
if fid.opened {
|
|
req.RespondError(Ebaduse)
|
|
return
|
|
}
|
|
|
|
if tc.Fid != tc.Newfid {
|
|
req.Newfid = conn.FidNew(tc.Newfid)
|
|
if req.Newfid == nil {
|
|
req.RespondError(Einuse)
|
|
return
|
|
}
|
|
|
|
req.Newfid.User = fid.User
|
|
req.Newfid.Type = fid.Type
|
|
} else {
|
|
req.Newfid = req.Fid
|
|
req.Newfid.IncRef()
|
|
}
|
|
|
|
(req.Conn.Srv.ops).(SrvReqOps).Walk(req)
|
|
}
|
|
|
|
func (srv *Srv) walkPost(req *SrvReq) {
|
|
rc := req.Rc
|
|
if rc == nil || rc.Type != Rwalk || req.Newfid == nil {
|
|
return
|
|
}
|
|
|
|
n := len(rc.Wqid)
|
|
if n > 0 {
|
|
req.Newfid.Type = rc.Wqid[n-1].Type
|
|
} else {
|
|
req.Newfid.Type = req.Fid.Type
|
|
}
|
|
|
|
// Don't retain the fid if only a partial walk succeeded
|
|
if n != len(req.Tc.Wname) {
|
|
return
|
|
}
|
|
|
|
if req.Newfid.fid != req.Fid.fid {
|
|
req.Newfid.IncRef()
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) open(req *SrvReq) {
|
|
fid := req.Fid
|
|
tc := req.Tc
|
|
if fid.opened {
|
|
req.RespondError(Eopen)
|
|
return
|
|
}
|
|
|
|
if (fid.Type&QTDIR) != 0 && tc.Mode != OREAD {
|
|
req.RespondError(Eperm)
|
|
return
|
|
}
|
|
|
|
fid.Omode = tc.Mode
|
|
(req.Conn.Srv.ops).(SrvReqOps).Open(req)
|
|
}
|
|
|
|
func (srv *Srv) openPost(req *SrvReq) {
|
|
if req.Fid != nil {
|
|
req.Fid.opened = req.Rc != nil && req.Rc.Type == Ropen
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) create(req *SrvReq) {
|
|
fid := req.Fid
|
|
tc := req.Tc
|
|
if fid.opened {
|
|
req.RespondError(Eopen)
|
|
return
|
|
}
|
|
|
|
if (fid.Type & QTDIR) == 0 {
|
|
req.RespondError(Enotdir)
|
|
return
|
|
}
|
|
|
|
/* can't open directories for other than reading */
|
|
if (tc.Perm&DMDIR) != 0 && tc.Mode != OREAD {
|
|
req.RespondError(Eperm)
|
|
return
|
|
}
|
|
|
|
/* can't create special files if not 9P2000.u */
|
|
if (tc.Perm&(DMNAMEDPIPE|DMSYMLINK|DMLINK|DMDEVICE|DMSOCKET)) != 0 && !req.Conn.Dotu {
|
|
req.RespondError(Eperm)
|
|
return
|
|
}
|
|
|
|
fid.Omode = tc.Mode
|
|
(req.Conn.Srv.ops).(SrvReqOps).Create(req)
|
|
}
|
|
|
|
func (srv *Srv) createPost(req *SrvReq) {
|
|
if req.Rc != nil && req.Rc.Type == Rcreate && req.Fid != nil {
|
|
req.Fid.Type = req.Rc.Qid.Type
|
|
req.Fid.opened = true
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) read(req *SrvReq) {
|
|
tc := req.Tc
|
|
fid := req.Fid
|
|
if tc.Count+IOHDRSZ > req.Conn.Msize {
|
|
req.RespondError(Etoolarge)
|
|
return
|
|
}
|
|
|
|
if (fid.Type & QTAUTH) != 0 {
|
|
var n int
|
|
|
|
rc := req.Rc
|
|
err := InitRread(rc, tc.Count)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
return
|
|
}
|
|
|
|
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
|
n, err = op.AuthRead(fid, tc.Offset, rc.Data)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
return
|
|
}
|
|
|
|
SetRreadCount(rc, uint32(n))
|
|
req.Respond()
|
|
} else {
|
|
req.RespondError(Enotimpl)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if (fid.Type & QTDIR) != 0 {
|
|
if tc.Offset == 0 {
|
|
fid.Diroffset = 0
|
|
} else if tc.Offset != fid.Diroffset {
|
|
fid.Diroffset = tc.Offset
|
|
}
|
|
}
|
|
|
|
(req.Conn.Srv.ops).(SrvReqOps).Read(req)
|
|
}
|
|
|
|
func (srv *Srv) readPost(req *SrvReq) {
|
|
if req.Rc != nil && req.Rc.Type == Rread && (req.Fid.Type&QTDIR) != 0 {
|
|
req.Fid.Diroffset += uint64(req.Rc.Count)
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) write(req *SrvReq) {
|
|
fid := req.Fid
|
|
tc := req.Tc
|
|
if (fid.Type & QTAUTH) != 0 {
|
|
tc := req.Tc
|
|
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
|
n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
|
|
if err != nil {
|
|
req.RespondError(err)
|
|
} else {
|
|
req.RespondRwrite(uint32(n))
|
|
}
|
|
} else {
|
|
req.RespondError(Enotimpl)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if !fid.opened || (fid.Type&QTDIR) != 0 || (fid.Omode&3) == OREAD {
|
|
req.RespondError(Ebaduse)
|
|
return
|
|
}
|
|
|
|
if tc.Count+IOHDRSZ > req.Conn.Msize {
|
|
req.RespondError(Etoolarge)
|
|
return
|
|
}
|
|
|
|
(req.Conn.Srv.ops).(SrvReqOps).Write(req)
|
|
}
|
|
|
|
func (srv *Srv) clunk(req *SrvReq) {
|
|
fid := req.Fid
|
|
if (fid.Type & QTAUTH) != 0 {
|
|
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
|
op.AuthDestroy(fid)
|
|
req.RespondRclunk()
|
|
} else {
|
|
req.RespondError(Enotimpl)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
(req.Conn.Srv.ops).(SrvReqOps).Clunk(req)
|
|
}
|
|
|
|
func (srv *Srv) clunkPost(req *SrvReq) {
|
|
if req.Rc != nil && req.Rc.Type == Rclunk && req.Fid != nil {
|
|
req.Fid.DecRef()
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) remove(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Remove(req) }
|
|
|
|
func (srv *Srv) removePost(req *SrvReq) {
|
|
if req.Rc != nil && req.Fid != nil {
|
|
req.Fid.DecRef()
|
|
}
|
|
}
|
|
|
|
func (srv *Srv) stat(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Stat(req) }
|
|
|
|
func (srv *Srv) wstat(req *SrvReq) {
|
|
/*
|
|
fid := req.Fid
|
|
d := &req.Tc.Dir
|
|
if d.Type != uint16(0xFFFF) || d.Dev != uint32(0xFFFFFFFF) || d.Version != uint32(0xFFFFFFFF) ||
|
|
d.Path != uint64(0xFFFFFFFFFFFFFFFF) {
|
|
req.RespondError(Eperm)
|
|
return
|
|
}
|
|
|
|
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&QTDIR) != 0 && (d.Mode&DMDIR) == 0) ||
|
|
((d.Type&QTDIR) == 0 && (d.Mode&DMDIR) != 0)) {
|
|
req.RespondError(Edirchange)
|
|
return
|
|
}
|
|
*/
|
|
|
|
(req.Conn.Srv.ops).(SrvReqOps).Wstat(req)
|
|
}
|