mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-22 13:05:36 +03:00
53 lines
1.9 KiB
Go
53 lines
1.9 KiB
Go
|
// Package aghrenameio is a wrapper around package github.com/google/renameio/v2
|
||
|
// that provides a similar stream-based API for both Unix and Windows systems.
|
||
|
// While the Windows API is not technically atomic, it still provides a
|
||
|
// consistent stream-based interface, and atomic renames of files do not seem to
|
||
|
// be possible in all cases anyway.
|
||
|
//
|
||
|
// See https://github.com/google/renameio/issues/1.
|
||
|
//
|
||
|
// TODO(a.garipov): Consider moving to golibs/renameioutil once tried and
|
||
|
// tested.
|
||
|
package aghrenameio
|
||
|
|
||
|
import (
|
||
|
"io/fs"
|
||
|
|
||
|
"github.com/AdguardTeam/golibs/errors"
|
||
|
)
|
||
|
|
||
|
// PendingFile is the interface for pending temporary files.
|
||
|
type PendingFile interface {
|
||
|
// Cleanup closes the file, and removes it without performing the renaming.
|
||
|
// To close and rename the file, use CloseReplace.
|
||
|
Cleanup() (err error)
|
||
|
|
||
|
// CloseReplace closes the temporary file and replaces the destination file
|
||
|
// with it, possibly atomically.
|
||
|
//
|
||
|
// This method is not safe for concurrent use by multiple goroutines.
|
||
|
CloseReplace() (err error)
|
||
|
|
||
|
// Write writes len(b) bytes from b to the File. It returns the number of
|
||
|
// bytes written and an error, if any. Write returns a non-nil error when n
|
||
|
// != len(b).
|
||
|
Write(b []byte) (n int, err error)
|
||
|
}
|
||
|
|
||
|
// NewPendingFile is a wrapper around [renameio.NewPendingFile] on Unix systems
|
||
|
// and [os.CreateTemp] on Windows.
|
||
|
func NewPendingFile(filePath string, mode fs.FileMode) (f PendingFile, err error) {
|
||
|
return newPendingFile(filePath, mode)
|
||
|
}
|
||
|
|
||
|
// WithDeferredCleanup is a helper that performs the necessary cleanups and
|
||
|
// finalizations of the temporary files based on the returned error.
|
||
|
func WithDeferredCleanup(returned error, file PendingFile) (err error) {
|
||
|
// Make sure that any error returned from here is marked as a deferred one.
|
||
|
if returned != nil {
|
||
|
return errors.WithDeferred(returned, file.Cleanup())
|
||
|
}
|
||
|
|
||
|
return errors.WithDeferred(nil, file.CloseReplace())
|
||
|
}
|