github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/libs/os/os_test.go (about)

     1  package os
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestCopyFile(t *testing.T) {
    15  	tmpfile, err := ioutil.TempFile("", "example")
    16  	if err != nil {
    17  		t.Fatal(err)
    18  	}
    19  	defer os.Remove(tmpfile.Name())
    20  	content := []byte("hello world")
    21  	if _, err := tmpfile.Write(content); err != nil {
    22  		t.Fatal(err)
    23  	}
    24  
    25  	copyfile := fmt.Sprintf("%s.copy", tmpfile.Name())
    26  	if err := CopyFile(tmpfile.Name(), copyfile); err != nil {
    27  		t.Fatal(err)
    28  	}
    29  	if _, err := os.Stat(copyfile); os.IsNotExist(err) {
    30  		t.Fatal("copy should exist")
    31  	}
    32  	data, err := ioutil.ReadFile(copyfile)
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	if !bytes.Equal(data, content) {
    37  		t.Fatalf("copy file content differs: expected %v, got %v", content, data)
    38  	}
    39  	os.Remove(copyfile)
    40  }
    41  
    42  func TestEnsureDir(t *testing.T) {
    43  	tmp, err := ioutil.TempDir("", "ensure-dir")
    44  	require.NoError(t, err)
    45  	defer os.RemoveAll(tmp)
    46  
    47  	// Should be possible to create a new directory.
    48  	err = EnsureDir(filepath.Join(tmp, "dir"), 0755)
    49  	require.NoError(t, err)
    50  	require.DirExists(t, filepath.Join(tmp, "dir"))
    51  
    52  	// Should succeed on existing directory.
    53  	err = EnsureDir(filepath.Join(tmp, "dir"), 0755)
    54  	require.NoError(t, err)
    55  
    56  	// Should fail on file.
    57  	err = ioutil.WriteFile(filepath.Join(tmp, "file"), []byte{}, 0644)
    58  	require.NoError(t, err)
    59  	err = EnsureDir(filepath.Join(tmp, "file"), 0755)
    60  	require.Error(t, err)
    61  
    62  	// Should allow symlink to dir.
    63  	err = os.Symlink(filepath.Join(tmp, "dir"), filepath.Join(tmp, "linkdir"))
    64  	require.NoError(t, err)
    65  	err = EnsureDir(filepath.Join(tmp, "linkdir"), 0755)
    66  	require.NoError(t, err)
    67  
    68  	// Should error on symlink to file.
    69  	err = os.Symlink(filepath.Join(tmp, "file"), filepath.Join(tmp, "linkfile"))
    70  	require.NoError(t, err)
    71  	err = EnsureDir(filepath.Join(tmp, "linkfile"), 0755)
    72  	require.Error(t, err)
    73  }
    74  
    75  // Ensure that using CopyFile does not truncate the destination file before
    76  // the origin is positively a non-directory and that it is ready for copying.
    77  // See https://github.com/tendermint/tendermint/issues/6427
    78  func TestTrickedTruncation(t *testing.T) {
    79  	tmpDir, err := ioutil.TempDir(os.TempDir(), "pwn_truncate")
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	defer os.Remove(tmpDir)
    84  
    85  	originalWALPath := filepath.Join(tmpDir, "wal")
    86  	originalWALContent := []byte("I AM BECOME DEATH, DESTROYER OF ALL WORLDS!")
    87  	if err := ioutil.WriteFile(originalWALPath, originalWALContent, 0755); err != nil {
    88  		t.Fatal(err)
    89  	}
    90  
    91  	// 1. Sanity check.
    92  	readWAL, err := ioutil.ReadFile(originalWALPath)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  	if !bytes.Equal(readWAL, originalWALContent) {
    97  		t.Fatalf("Cannot proceed as the content does not match\nGot:  %q\nWant: %q", readWAL, originalWALContent)
    98  	}
    99  
   100  	// 2. Now cause the truncation of the original file.
   101  	// It is absolutely legal to invoke os.Open on a directory.
   102  	if err := CopyFile(tmpDir, originalWALPath); err == nil {
   103  		t.Fatal("Expected an error")
   104  	}
   105  
   106  	// 3. Check the WAL's content
   107  	reReadWAL, err := ioutil.ReadFile(originalWALPath)
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	if !bytes.Equal(reReadWAL, originalWALContent) {
   112  		t.Fatalf("Oops, the WAL's content was changed :(\nGot:  %q\nWant: %q", reReadWAL, originalWALContent)
   113  	}
   114  }