afero
afero copied to clipboard
Renaming a file using MemMapFs behaves differently to OsFs
The memory mapped FS differs in behaviour when renaming a file compared with the OsFs one. Essentially in a memory mapped filesystem the Rename()
operation takes effect on any existing afero.File
instances pointing to the file which gets renamed.
package main
import (
"log"
"github.com/spf13/afero"
)
func main() {
// fs := afero.NewOsFs()
fs := afero.NewMemMapFs()
f, err := afero.TempFile(fs, "", "temp*")
if err != nil {
log.Fatal(err)
}
ogFName := f.Name()
log.Printf("Pre-rename: %s", f.Name())
err = f.Close()
if err != nil {
log.Fatal(err)
}
err = fs.Rename(f.Name(), "new-name")
if err != nil {
log.Fatal(err)
}
log.Printf("Post-rename: %s", f.Name())
err = fs.RemoveAll(f.Name())
if err != nil {
log.Fatal(err)
}
err = fs.RemoveAll(ogFName)
if err != nil {
log.Fatal(err)
}
}
Using OsFs
go run main.go
2021/11/10 14:28:28 Pre-rename: /tmp/temp796650521
2021/11/10 14:28:28 Post-rename: /tmp/temp796650521
Using MemMapFs
go run main.go
2021/11/10 14:28:34 Pre-rename: /tmp/temp291024985
2021/11/10 14:28:34 Post-rename: new-name
I think the issue lies in the following code because the mem.FileData
is a pointer and that gets copied into the new location within the map:
if _, ok := m.getData()[oldname]; ok {
m.mu.RUnlock()
m.mu.Lock()
m.unRegisterWithParent(oldname)
fileData := m.getData()[oldname] // <------ This fileData is already referenced by our afero.File variable.
delete(m.getData(), oldname)
mem.ChangeFileName(fileData, newname) // <---- This alters the name which results in our afero.File.Name() getting updated too.
m.getData()[newname] = fileData
m.registerWithParent(fileData, 0)
m.mu.Unlock()
m.mu.RLock()
https://github.com/spf13/afero/blob/949437f3b7e2f3ca7ad553780aec516d0fc310d2/memmap.go#L303-L313