From ece6c19fa6e6b03db9b0274f038d8c0e295d0608 Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:13:01 +0200 Subject: [PATCH] =?UTF-8?q?9p:=20fix=20/net/dns=20read=20pattern=20?= =?UTF-8?q?=E2=80=94=20ignore=20offset=20for=20write-then-read?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shell fd position advances after write, so the subsequent read arrives with offset=N (write length). readDNS always serves from offset 0, fixing empty reads from exec 3<>file; echo >&3; cat <&3. --- server/server.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/server/server.go b/server/server.go index e9f7521..f99258c 100644 --- a/server/server.go +++ b/server/server.go @@ -757,22 +757,22 @@ func (s *Server) read(cs *connState, fc *plan9.Fcall, ctx context.Context) *plan return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: uint32(len(data)), Data: data} } - // /complete: return per-fid result from previous write + // /complete: return per-fid result from previous write (offset 0-based) if path == "/complete" { s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) - return s.readSlice(fc, f.completeResult) + return s.readDNS(fc, f.completeResult) } - // /generate: return per-fid result from previous write + // /generate: return per-fid result from previous write (offset 0-based) if path == "/generate" { s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) - return s.readSlice(fc, f.generateResult) + return s.readDNS(fc, f.generateResult) } - // /route: return per-fid result from previous write + // /route: return per-fid result from previous write (offset 0-based) if path == "/route" { s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) - return s.readSlice(fc, f.routeResult) + return s.readDNS(fc, f.routeResult) } s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) @@ -850,6 +850,21 @@ func (s *Server) readSlice(fc *plan9.Fcall, content []byte) *plan9.Fcall { return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: uint32(len(data)), Data: data} } +// readDNS implements the Plan 9 /net/dns read pattern: the result is always +// read from offset 0 regardless of the client's file position (which advances +// after a write). This allows write-then-read on the same fd. +func (s *Server) readDNS(fc *plan9.Fcall, content []byte) *plan9.Fcall { + var data []byte + if len(content) > 0 { + end := int(fc.Count) + if end > len(content) { + end = len(content) + } + data = content[:end] + } + return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Count: uint32(len(data)), Data: data} +} + func (s *Server) helpPath() string { return paths.CfgDir() + "/help.md" }