spf13 / afero

A FileSystem Abstraction System for Go
Apache License 2.0
5.79k stars 498 forks source link

memfs vs osfs behavior differences #412

Open shadowspore opened 6 months ago

shadowspore commented 6 months ago

I've noticed a behavior difference between memfs and real os filesystem. Related issue: https://github.com/spf13/afero/issues/152 Related commit: https://github.com/spf13/afero/commit/ec3a3111d1e1bdff38a61e09d5a5f5e974905611 It says that returning io.ErrUnexpectedEOF is "in line with how the OS File works". However, it seems that this is not true? ping @bep

Test case to reproduce (tested on linux 6.6.7 ext4):

package filebase

import (
    "os"
    "testing"

    "github.com/spf13/afero"
    "github.com/stretchr/testify/require"
)

func TestAferoMemfs(t *testing.T) {
    memfs := afero.NewMemMapFs()
    osfs := afero.NewOsFs()

    // Create files.
    fmem, err := memfs.OpenFile("/tmp/foo.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
    require.NoError(t, err)

    freal, err := osfs.OpenFile("/tmp/foo.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
    require.NoError(t, err)

    // Write data and close files.
    {
        _, err = fmem.WriteString("abc")
        require.NoError(t, err)

        _, err = freal.WriteString("abc")
        require.NoError(t, err)

        require.NoError(t, fmem.Close())
        require.NoError(t, freal.Close())
    }

    // Open files again.
    fmem, err = memfs.OpenFile("/tmp/foo.txt", os.O_RDWR, 0o600)
    require.NoError(t, err)

    freal, err = osfs.OpenFile("/tmp/foo.txt", os.O_RDWR, 0o600)
    require.NoError(t, err)

    // Read data and truncate.
    {
        bufMem := make([]byte, 5)
        nMem, errMem := fmem.Read(bufMem)

        bufReal := make([]byte, 5)
        nReal, errReal := freal.Read(bufReal)

        require.Equal(t, errMem, errReal)
        require.Equal(t, nMem, nReal)
        require.Equal(t, bufMem, bufReal)

        require.NoError(t, fmem.Truncate(0))
        require.NoError(t, freal.Truncate(0))
    }

    // Try to read data again.
    {
        bufMem := make([]byte, 5)
        nMem, errMem := fmem.Read(bufMem)

        bufReal := make([]byte, 5)
        nReal, errReal := freal.Read(bufReal)

        require.Equal(t, errMem, errReal) // <- UnexpectedEOF vs EOF
        require.Equal(t, nMem, nReal)
        require.Equal(t, bufMem, bufReal)
    }
}