Mercurial > gemma
view pkg/misc/tmpfiles.go @ 5652:9b3779f649c2 v5.7.1
Bumped version for release.
author | Sascha Wilde <wilde@sha-bang.de> |
---|---|
date | Mon, 07 Aug 2023 17:59:18 +0200 |
parents | 5f47eeea988d |
children |
line wrap: on
line source
// This is Free Software under GNU Affero General Public License v >= 3.0 // without warranty, see README.md and license for details. // // SPDX-License-Identifier: AGPL-3.0-or-later // License-Filename: LICENSES/AGPL-3.0.txt // // Copyright (C) 2018 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> package misc import ( "encoding/hex" "os" "path/filepath" "sort" "sync" "time" "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/config" "gemma.intevation.de/gemma/pkg/log" ) const ( tmpFilesDir = "tmpfiles" maxTmpFiles = 100 maxTmpFileAge = 45 * time.Minute tmpfilesCleanUp = 15 * time.Minute ) var tmpfilesMu sync.Mutex func init() { go func() { config.WaitReady() for { if err := cleanupTmpFiles(); err != nil { log.Errorf("%v\n", err) } time.Sleep(tmpfilesCleanUp) } }() } func tmpfilesDir() string { dir := config.TmpDir() if dir == "" { dir = os.TempDir() } return filepath.Join(dir, tmpFilesDir) } func cleanupTmpFiles() error { tmpfilesMu.Lock() defer tmpfilesMu.Unlock() tmp := tmpfilesDir() _, err := os.Stat(tmp) switch { case os.IsNotExist(err): return nil case err != nil: return err } f, err := os.Open(tmp) if err != nil { return err } files, err := f.Readdir(-1) f.Close() if err != nil { return err } bestBefore := time.Now().Add(-maxTmpFileAge) var errs []error var deleted int for _, fi := range files { if fi.ModTime().Before(bestBefore) { fname := filepath.Join(tmp, fi.Name()) if err := os.RemoveAll(fname); err != nil { errs = append(errs, err) } else { deleted++ } } } // If empty remove temp folder. if deleted == len(files) { if err := os.RemoveAll(tmp); err != nil { errs = append(errs, err) } } if len(errs) > 0 { return common.ToError(errs) } return nil } // DeleteTempFile deletes a file identified by its token // from the special folder of temporary files. func DeleteTempFile(token string) error { tmpfilesMu.Lock() defer tmpfilesMu.Unlock() tmp := tmpfilesDir() return os.RemoveAll(filepath.Join(tmp, token)) } // UnmakeTempFile moves a file identified by a token // back from the special folder to a normal path. // This only will succeed if the token is not expired. func UnmakeTempFile(token, path string) error { tmpfilesMu.Lock() defer tmpfilesMu.Unlock() tmp := tmpfilesDir() return os.Rename(filepath.Join(tmp, token), path) } // MakeTempFile moves a file into a special temporary file folder // and returns a token for later accessing the file again. // Files in this special folder are only quaranteed to be // kept alive among of time. After this time expires file // will be likely to be deleted. There are only a limited // amount of temporary files allowed. If you push more // files into the special folder the oldest will be erased. func MakeTempFile(fname string) (string, error) { tmpfilesMu.Lock() defer tmpfilesMu.Unlock() tmp := tmpfilesDir() _, err := os.Stat(tmp) switch { case os.IsNotExist(err): if err := os.MkdirAll(tmp, 0700); err != nil { return "", err } case err != nil: return "", err } f, err := os.Open(tmp) if err != nil { return "", err } files, err := f.Readdir(-1) f.Close() if err != nil { return "", err } // If there are too many throw away old. if len(files) >= maxTmpFiles { sort.Slice(files, func(i, j int) bool { return files[i].ModTime().Before(files[j].ModTime()) }) var errs []error for len(files) >= maxTmpFiles { fname := filepath.Join(tmp, files[0].Name()) if err := os.RemoveAll(fname); err != nil { errs = append(errs, err) } files = files[1:] } if len(errs) > 0 { return "", common.ToError(errs) } } var token string again: token = generateToken() for _, f := range files { if f.Name() == token { goto again } } err = os.Rename(fname, filepath.Join(tmp, token)) return token, err } func generateToken() string { return hex.EncodeToString(common.GenerateRandomKey(20)) }