forked from TrueCloudLab/restic
54 lines
1.3 KiB
Go
54 lines
1.3 KiB
Go
package fs
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"runtime/debug"
|
|
)
|
|
|
|
// Track is a wrapper around another file system which installs finalizers
|
|
// for open files which call panic() when they are not closed when the garbage
|
|
// collector releases them. This can be used to find resource leaks via open
|
|
// files.
|
|
type Track struct {
|
|
FS
|
|
}
|
|
|
|
// Open wraps the Open method of the underlying file system.
|
|
func (fs Track) Open(name string) (File, error) {
|
|
f, err := fs.FS.Open(fixpath(name))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newTrackFile(debug.Stack(), name, f), nil
|
|
}
|
|
|
|
// OpenFile wraps the OpenFile method of the underlying file system.
|
|
func (fs Track) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
|
|
f, err := fs.FS.OpenFile(fixpath(name), flag, perm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newTrackFile(debug.Stack(), name, f), nil
|
|
}
|
|
|
|
type trackFile struct {
|
|
File
|
|
}
|
|
|
|
func newTrackFile(stack []byte, filename string, file File) *trackFile {
|
|
f := &trackFile{file}
|
|
runtime.SetFinalizer(f, func(_ *trackFile) {
|
|
fmt.Fprintf(os.Stderr, "file %s not closed\n\nStacktrack:\n%s\n", filename, stack)
|
|
panic("file " + filename + " not closed")
|
|
})
|
|
return f
|
|
}
|
|
|
|
func (f *trackFile) Close() error {
|
|
runtime.SetFinalizer(f, nil)
|
|
return f.File.Close()
|
|
}
|