func (s *Session) handleTwalk(cx context.Context, msg styxproto.Twalk, file file) bool { newfid := msg.Newfid() // Cannot use "opened" (ready for IO) fids for walking; see walk(5) // in 9P manual. However, 9pfuse does this, so we'll allow it. //if file.rwc != nil { // s.conn.Rerror(msg.Tag(), "walk on opened fid") // s.conn.Flush() // return true //} // newfid must be unused or equal to fid if newfid != msg.Fid() { if _, ok := s.conn.sessionFid.Get(newfid); ok { s.conn.clearTag(msg.Tag()) s.conn.Rerror(msg.Tag(), "Twalk: fid %x already in use", newfid) s.conn.Flush() return true } } // NOTE(droyo) The clone usage of Twalk is hidden from the user // of the styx package; we assume that all clients who have procured // a fid for a file are permitted to clone that fid, and may do so without // side effects. if msg.Nwname() == 0 { if newfid != msg.Fid() { s.files.Put(newfid, file) s.conn.sessionFid.Put(newfid, s) s.IncRef() } s.conn.clearTag(msg.Tag()) s.conn.Rwalk(msg.Tag()) s.conn.Flush() return true } // see walk.go for more details elem := make([]string, 0, msg.Nwname()) for i := 0; i < cap(elem); i++ { elem = append(elem, string(msg.Wname(i))) } walker := newWalker(s, cx, msg, file.name, elem...) for i := range elem { fullpath := path.Join(file.name, strings.Join(elem[:i+1], "/")) s.requests <- Twalk{ index: i, walk: walker, reqInfo: newReqInfo(cx, s, msg, fullpath), } } return true }
func newWalker(s *Session, cx context.Context, msg styxproto.Twalk, base string, elem ...string) *walker { qids := make([]styxproto.Qid, len(elem)) found := qids[:0] newpath := path.Join(base, strings.Join(elem, "/")) w := &walker{ qids: qids, found: found, filled: make([]int32, len(elem)), complete: make(chan struct{}), collect: make(chan walkElem), session: s, newfid: msg.Newfid(), path: newpath, tag: msg.Tag(), cx: cx, } go w.run() return w }