From 357096e924ddf6ea598254835e8596d952630ee1 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 28 Sep 2026 19:25:15 +0200 Subject: [PATCH] libnetwork/etchosts: keep file open when updating hosts Open the hosts file once for both reading and writing, instead of reading and writing it through separate file operations. This keeps the update on the same file handle, avoids reopening the path between the read and write, and preserves the existing file metadata. Signed-off-by: Sebastiaan van Stijn --- daemon/libnetwork/etchosts/etchosts.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/daemon/libnetwork/etchosts/etchosts.go b/daemon/libnetwork/etchosts/etchosts.go index 51ad0040ed..d70b6fd0c7 100644 --- a/daemon/libnetwork/etchosts/etchosts.go +++ b/daemon/libnetwork/etchosts/etchosts.go @@ -169,16 +169,32 @@ loop: // path is path to host file // IP is new IP address // hostname is hostname to search for to replace IP -func Update(path, IP, hostname string) error { +func Update(path, IP, hostname string) (retErr error) { re, err := regexp.Compile(fmt.Sprintf(`(\S*)(\t%s)(\s|\.)`, regexp.QuoteMeta(hostname))) if err != nil { return err } - defer pathLock(path)() - old, err := os.ReadFile(path) + defer pathLock(path)() + f, err := os.OpenFile(path, os.O_RDWR, 0) if err != nil { return err } - return os.WriteFile(path, re.ReplaceAll(old, []byte(IP+"$2"+"$3")), 0o644) // #nosec G703 -- path argument is from trusted source. + defer func() { + if err := f.Close(); retErr == nil { + retErr = err + } + }() + + old, err := io.ReadAll(f) + if err != nil { + return err + } + updated := re.ReplaceAll(old, []byte(IP+"$2"+"$3")) + + if err := f.Truncate(0); err != nil { + return err + } + _, err = f.WriteAt(updated, 0) + return err }