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