From 868cf6745f218458688c16a990c8160468419c43 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 7 Sep 2022 16:43:40 -0400 Subject: [PATCH] internal/gcsfs: hide OS files until Close GCS doesn't show you in-progress files, and I wrote various await functions under that assumption. The local filesystem didn't match that behavior, which led to empty files being read. Emulate GCS by writing to a hidden temp file that's renamed to the real name upon Close. Fixes golang/go#53972. (I hope.) Change-Id: I34ec484128e417c4b9f6c7d0731df5fdabac652b Reviewed-on: https://go-review.googlesource.com/c/build/+/429275 Run-TryBot: Heschi Kreinick Reviewed-by: Jenny Rakoczy TryBot-Result: Gopher Robot Auto-Submit: Heschi Kreinick --- internal/gcsfs/osfs.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/internal/gcsfs/osfs.go b/internal/gcsfs/osfs.go index d4748b26bf..ffdf20029c 100644 --- a/internal/gcsfs/osfs.go +++ b/internal/gcsfs/osfs.go @@ -63,11 +63,35 @@ func (dir dirFS) Create(name string) (WriteFile, error) { if err := os.MkdirAll(path.Dir(fullName), 0700); err != nil { return nil, err } - f, err := os.Create(fullName) + + // GCS doesn't let you see a file until you're done writing it. Write + // to a temp file, which will be renamed to the expected name on Close. + temp, err := os.CreateTemp(path.Dir(fullName), "."+path.Base(fullName)+".writing-*") if err != nil { return nil, err } - return f, nil + finalize := func() error { + return os.Rename(temp.Name(), fullName) + } + return &writingFile{temp, finalize}, nil +} + +type writingFile struct { + *os.File + finalize func() error +} + +func (wf *writingFile) Close() error { + if err := wf.File.Close(); err != nil { + return err + } + if wf.finalize != nil { + if err := wf.finalize(); err != nil { + return err + } + wf.finalize = nil + } + return nil } func (dir dirFS) Sub(subDir string) (fs.FS, error) {