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)
 | 
						|
}
 |