func (u *VuFs) Read(req *srv.Req) { fid := req.Fid.Aux.(*Fid) tc := req.Tc rc := req.Rc st, err := os.Stat(fid.path) if err != nil { req.RespondError(err) return } p.InitRread(rc, tc.Count) var count int var e error if st.IsDir() { // Simpler to treat non-zero offset as an error for directories. if tc.Offset != 0 { req.RespondError(srv.Ebadoffset) return } dirs, e := fid.file.Readdir(-1) if e != nil { req.RespondError(toError(e)) return } // Bytes/one packed dir = 49 + len(name) + len(uid) + len(gid) + len(muid) // Estimate 49 + 20 + 20 + 20 + 11 // From ../../lionkov/go9p/p/p9.go:421,427 dirents := make([]byte, 0, 120*len(dirs)) for i := 0; i < len(dirs); i++ { path := fid.path + "/" + dirs[i].Name() st, err := dir2Dir(path, dirs[i], req.Conn.Srv.Upool) if err != nil { req.RespondError(toError(err)) return } b := p.PackDir(st, false) dirents = append(dirents, b...) } if len(dirents) > int(tc.Count) { req.RespondError(srv.Etoolarge) return } copy(rc.Data, dirents) count = len(dirents) } else { count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset)) if e != nil && e != io.EOF { req.RespondError(toError(e)) return } } p.SetRreadCount(rc, uint32(count)) req.Respond() }
func (u *Ufs) Read(req *srv.Req) { dbg := u.Debuglevel&srv.DbgLogFcalls != 0 fid := req.Fid.Aux.(*Fid) tc := req.Tc rc := req.Rc err := fid.stat() if err != nil { req.RespondError(err) return } p.InitRread(rc, tc.Count) var count int var e error if fid.st.IsDir() { if tc.Offset == 0 { var e error // If we got here, it was open. Can't really seek // in most cases, just close and reopen it. fid.file.Close() if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil { req.RespondError(toError(e)) return } if fid.dirs, e = fid.file.Readdir(-1); e != nil { req.RespondError(toError(e)) return } if dbg { log.Printf("Read: read %d entries", len(fid.dirs)) } fid.dirents = nil fid.direntends = nil for i := 0; i < len(fid.dirs); i++ { path := fid.path + "/" + fid.dirs[i].Name() st, err := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool) if err != nil { if dbg { log.Printf("dbg: stat of %v: %v", path, err) } continue } if dbg { log.Printf("Stat: %v is %v", path, st) } b := p.PackDir(st, req.Conn.Dotu) fid.dirents = append(fid.dirents, b...) count += len(b) fid.direntends = append(fid.direntends, count) if dbg { log.Printf("fid.direntends is %v\n", fid.direntends) } } } switch { case tc.Offset > uint64(len(fid.dirents)): count = 0 case len(fid.dirents[tc.Offset:]) > int(tc.Count): count = int(tc.Count) default: count = len(fid.dirents[tc.Offset:]) } if dbg { log.Printf("readdir: count %v @ offset %v", count, tc.Offset) } nextend := sort.SearchInts(fid.direntends, int(tc.Offset)+count) if nextend < len(fid.direntends) { if fid.direntends[nextend] > int(tc.Offset)+count { if nextend > 0 { count = fid.direntends[nextend-1] - int(tc.Offset) } else { count = 0 } } } if dbg { log.Printf("readdir: count adjusted %v @ offset %v", count, tc.Offset) } if count == 0 && int(tc.Offset) < len(fid.dirents) && len(fid.dirents) > 0 { req.RespondError(&p.Error{"too small read size for dir entry", p.EINVAL}) return } copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count]) } else { count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset)) if e != nil && e != io.EOF { req.RespondError(toError(e)) return } } p.SetRreadCount(rc, uint32(count)) req.Respond() }