From b44ce18d54874f297dc6bac1409a1a9eac4d488e Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Sun, 26 Apr 2026 12:49:58 +0200 Subject: [PATCH] server: dispatch handleWrite on empty writes from writable fids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fids opened OWRITE or ORDWR with zero bytes written were silently dropped on clunk — the old writeBuf-length guard prevented handleWrite from being called, leaving the previous file content intact. Track writable by open mode instead, and remove the blanket empty-input early return in handleWrite. /s/new retains its own empty guard since a zero-byte write there is meaningless. Co-Authored-By: Claude Sonnet 4.6 --- server.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/server.go b/server.go index 902b829..3246dae 100644 --- a/server.go +++ b/server.go @@ -1032,16 +1032,18 @@ func (s *Server) clunk(cs *connState, fc *plan9.Fcall) *plan9.Fcall { f, ok := cs.fids[fc.Fid] var path string var data []byte + var writable bool if ok { - if len(f.writeBuf) > 0 { + if m := f.mode & 3; m == plan9.OWRITE || m == plan9.ORDWR { path = f.path + writable = true data = make([]byte, len(f.writeBuf)) copy(data, f.writeBuf) } delete(cs.fids, fc.Fid) } cs.mu.Unlock() - if len(data) > 0 { + if writable { s.log.Debug("Tclunk flush path=%q writeBuf=%d", path, len(data)) input := strings.TrimSpace(string(data)) if s.isAsyncWrite(path) { @@ -1120,11 +1122,11 @@ func (s *Server) remove(cs *connState, fc *plan9.Fcall) *plan9.Fcall { // as a goroutine because they block for the entire agent turn). func (s *Server) handleWrite(path, input string) error { s.log.Debug("handleWrite path=%q input_len=%d", path, len(input)) - if input == "" { - return nil - } if path == "/s/new" { + if input == "" { + return nil + } return storeWrite(s.sessionStore, "new", []byte(input)) }