// Stat produces a styxproto.Stat from an open file. If the value // provides a Stat method matching that of os.File, that is used. // Otherwise, the styxfile package determines the file's attributes // based on other characteristics. func Stat(buf []byte, file Interface, name string, qid styxproto.Qid) (styxproto.Stat, error) { var ( fi os.FileInfo err error ) type hasStat interface { Stat() (os.FileInfo, error) } if v, ok := file.(hasStat); ok { fi, err = v.Stat() if err != nil { return nil, err } } else { fi = statGuess{file, name, qid.Type()} } uid, gid, muid := sys.FileOwner(fi) stat, _, err := styxproto.NewStat(buf, fi.Name(), uid, gid, muid) if err != nil { return nil, err } stat.SetLength(fi.Size()) stat.SetMode(Mode9P(fi.Mode())) stat.SetAtime(uint32(fi.ModTime().Unix())) stat.SetMtime(uint32(fi.ModTime().Unix())) stat.SetQid(qid) return stat, nil }
// 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) } }
func (s *Session) handleTstat(cx context.Context, msg styxproto.Tstat, file file) bool { buf := make([]byte, styxproto.MaxStatLen) if file.auth { stat, _, err := styxproto.NewStat(buf, "", "", "", "") if err != nil { // input is not user-controlled, this should // never happen panic(err) } stat.SetMode(styxproto.DMAUTH) stat.SetQid(s.conn.qid("", styxproto.QTAUTH)) s.conn.clearTag(msg.Tag()) s.conn.Rstat(msg.Tag(), stat) s.conn.Flush() } else if file.rwc != nil { s.conn.clearTag(msg.Tag()) if qid, ok := s.conn.qidpool.Get(file.name); !ok { s.conn.Rerror(msg.Tag(), "qid for %s not found", file.name) } else if stat, err := styxfile.Stat(buf, file.rwc, file.name, qid); err != nil { s.conn.Rerror(msg.Tag(), "%s", err) } else { s.conn.Rstat(msg.Tag(), stat) } s.conn.Flush() } else { s.requests <- Tstat{ reqInfo: newReqInfo(cx, s, msg, file.name), } } return true }
func ExampleNewStat() { buf := make([]byte, 100) s, buf, err := styxproto.NewStat(buf, "messages.log", "root", "wheel", "") if err != nil { log.Fatal(err) } s.SetLength(309) s.SetMode(0640) fmt.Println(s) // Output: type=0 dev=0 qid="type=0 ver=0 path=0" mode=640 atime=0 mtime=0 length=309 name="messages.log" uid="root" gid="wheel" muid="" }
func blankStat(name, uid, gid string) styxproto.Stat { buf := make([]byte, styxproto.MaxStatLen) stat, _, err := styxproto.NewStat(buf, name, uid, gid, uid) if err != nil { panic(err) } stat.SetAtime(maxuint32) stat.SetMtime(maxuint32) stat.SetDev(maxuint32) stat.SetLength(-1) stat.SetMode(maxuint32) for i := range stat.Qid() { stat.Qid()[i] = 0xff } stat.SetType(maxuint16) return stat }
func marshalStats(buf []byte, files []os.FileInfo, dir string, pool *qidpool.Pool) (int, error) { var ( stat styxproto.Stat n = 0 err error ) for _, fi := range files { uid, gid, muid := sys.FileOwner(fi) stat, buf, err = styxproto.NewStat(buf, fi.Name(), uid, gid, muid) if err != nil { break } n += len(stat) mode := Mode9P(fi.Mode()) qtype := QidType(mode) stat.SetMtime(uint32(fi.ModTime().Unix())) stat.SetAtime(stat.Mtime()) stat.SetLength(fi.Size()) stat.SetMode(mode) stat.SetQid(pool.Put(path.Join(dir, fi.Name()), qtype)) } return n, err }