// Rcreate is used to respond to a succesful create request. With 9P, creating // a file also opens the file for I/O. Once Rcreate returns, future read // and write requests to the file handle will pass through rwc. The value // rwc must meet the same criteria listed for the Ropen method of a Topen // request. func (t Tcreate) Rcreate(rwc interface{}, err error) { var ( f styxfile.Interface ) if err != nil { t.Rerror("%s", err) return } if dir, ok := rwc.(Directory); t.Mode.IsDir() && ok { f = styxfile.NewDir(dir, path.Join(t.Path(), t.Name), t.session.conn.qidpool) } else { f, err = styxfile.New(rwc) } if err != nil { t.session.conn.srv.logf("create %s failed: %s", t.Name, err) t.Rerror("create failed") return } file := file{name: path.Join(t.Path(), t.Name), rwc: f} // fid for parent directory is now the fid for the new file, // so there is no increase in references to this session. t.session.files.Put(t.fid, file) qtype := styxfile.QidType(styxfile.Mode9P(t.Mode)) qid := t.session.conn.qid(file.name, qtype) t.session.unhandled = false if t.session.conn.clearTag(t.tag) { t.session.conn.Rcreate(t.tag, qid, 0) } }
// Rstat responds to a succesful Tstat request. The styx package will // translate the os.FileInfo value into the appropriate 9P structure. Rstat // will attempt to resolve the names of the file's owner and group. If // that cannot be done, an empty string is sent. If err is non-nil, and error // is sent to the client instead. func (t Tstat) Rstat(info os.FileInfo, err error) { if err != nil { t.Rerror("%s", err) return } buf := make([]byte, styxproto.MaxStatLen) uid, gid, muid := sys.FileOwner(info) name := info.Name() if name == "/" { name = "." } stat, _, err := styxproto.NewStat(buf, name, uid, gid, muid) if err != nil { // should never happen panic(err) } mode := styxfile.Mode9P(info.Mode()) stat.SetLength(info.Size()) stat.SetMode(mode) stat.SetAtime(uint32(info.ModTime().Unix())) // TODO: get atime stat.SetMtime(uint32(info.ModTime().Unix())) stat.SetQid(t.session.conn.qid(t.Path(), styxfile.QidType(mode))) t.session.unhandled = false if t.session.conn.clearTag(t.tag) { t.session.conn.Rstat(t.tag, stat) } }
// Rwalk signals to the client that the file named by the Twalk's // Path method exists and is of the given mode. The permission bits of // mode are ignored, and only the file type bits, such as os.ModeDir, // are sent to the client. If err is non-nil, an error response is sent to the // client instead. func (t Twalk) Rwalk(info os.FileInfo, err error) { var qid styxproto.Qid var mode os.FileMode if err == nil { mode = info.Mode() qid = t.session.conn.qid(t.Path(), styxfile.QidType(styxfile.Mode9P(mode))) } t.walk.filled[t.index] = 1 elem := walkElem{qid: qid, index: t.index, err: err} select { case t.walk.collect <- elem: case <-t.walk.complete: } }