From 56f012ceb6afa978274c2980e466e55bf0d2546d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Fri, 29 Nov 2024 14:16:07 +0100 Subject: [PATCH] fix: use a tmp file and rename to prevent a possible race condition --- .../pkg/thumbnail/storage/filesystem.go | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/services/thumbnails/pkg/thumbnail/storage/filesystem.go b/services/thumbnails/pkg/thumbnail/storage/filesystem.go index 0188fc8b43..621b2194fb 100644 --- a/services/thumbnails/pkg/thumbnail/storage/filesystem.go +++ b/services/thumbnails/pkg/thumbnail/storage/filesystem.go @@ -62,14 +62,29 @@ func (s FileSystem) Put(key string, img []byte) error { } if _, err := os.Stat(imgPath); os.IsNotExist(err) { - f, err := os.Create(imgPath) + f, err := os.CreateTemp(dir, "tmpthumb") if err != nil { - return errors.Wrapf(err, "could not create file \"%s\"", key) + return errors.Wrapf(err, "could not create temporary file for \"%s\"", key) } - defer f.Close() - if _, err = f.Write(img); err != nil { - return errors.Wrapf(err, "could not write to file \"%s\"", key) + _, writeErr := f.Write(img) // write the thumbnail in the temporary file + f.Close() // close the file regardless of the error + + // if there was a problem writing, remove the temporary file + if writeErr != nil { + if remErr := os.Remove(f.Name()); remErr != nil { + return errors.Wrapf(remErr, "could not cleanup temporary file for \"%s\"", key) + } + return errors.Wrapf(writeErr, "could not write to temporary file for \"%s\"", key) + } + + // rename the temporary file to the final file + if renErr := os.Rename(f.Name(), imgPath); renErr != nil { + // if we couldn't rename, remove the temporary file + if remErr := os.Remove(f.Name()); remErr != nil { + return errors.Wrapf(remErr, "rename failed and could not cleanup temporary file for \"%s\"", key) + } + return errors.Wrapf(err, "could not rename temporary file to \"%s\"", key) } }